diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 000000000000..4521bc876a8f --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,101 @@ +# 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 2022 + +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" + +# We always use a 64-bit machine, but can build x86 distributions +# with the PYTHON_ARCH variable +platform: + - x64 + +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: + - set EXTRA_PACKAGES=pywin32 codecov + # These are optional dependencies so that we don't skip so many tests... + - set EXTRA_PACKAGES=%EXTRA_PACKAGES% 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 + + - micromamba env create -f environment.yml python=%PYTHON_VERSION% %EXTRA_PACKAGES% + - micromamba activate mpl-dev + +build_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' + +test_script: + # 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: + - codecov -e PYTHON_VERSION PLATFORM -n "%PYTHON_VERSION% Windows" + +on_failure: + # Generate an 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..85622ffa7013 --- /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-5 + - 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-5 + 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 --group build + python -m pip install --user \ + numpy<< parameters.numpy_version >> \ + --group doc + 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-3 + 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..f3595d2b7865 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,89 @@ +--- +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 + - pixi + - uv + - 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..635f11028226 --- /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://discourse.matplotlib.org/chat/c/matplotlib/2 + 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..e66cac52f9c9 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,39 @@ + + +## PR summary + + +## AI Disclosure + + +## 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..d391ab4a18eb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,21 @@ +--- +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + groups: + actions: + patterns: + - "*" + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + exclude-paths: + - "ci/minver-requirements.txt" + - package-ecosystem: "pre-commit" + directory: "/" + schedule: + interval: "monthly" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000000..77b79146b47f --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,284 @@ +--- +"CI: Run cibuildwheel": + - changed-files: + - any-glob-to-any-file: + - '.github/workflows/cibuildwheel.yml' + - '.github/workflows/wasm.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/autoclose_comment.yml b/.github/workflows/autoclose_comment.yml new file mode 100644 index 000000000000..4d18d82a801f --- /dev/null +++ b/.github/workflows/autoclose_comment.yml @@ -0,0 +1,80 @@ +--- +name: autoclose comment +# Post comment on PRs when labeled with "status: autoclose candidate". +# Based on scikit-learn's autoclose bot at +# https://github.com/scikit-learn/scikit-learn/blob/main/.github/workflows/autoclose-comment.yml + +permissions: + contents: read + pull-requests: write + +on: + pull_request_target: + types: + - labeled + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + +jobs: + post_comment: + name: post_comment + if: "${{ contains(github.event.label.name, 'status: autoclose candidate') }}" + runs-on: ubuntu-latest + + steps: + + - name: comment on potential autoclose + run: | + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/$GH_REPO/issues/$PULL_REQUEST_NUMBER/comments \ + -f "body=$BODY" + env: + BODY: > + ⏰ This pull request might be automatically closed in two weeks from now. + + + Thank you for your contribution to Matplotlib and for the effort you + have put into this PR. This pull request does not yet meet the + quality and clarity standards needed for an effective review. + Project maintainers have limited time for code reviews, and our goal + is to prioritize well-prepared contributions to keep Matplotlib + maintainable. + + + Matplotlib maintainers cannot provide one-to-one guidance on this PR. + However, if you ask focused, well-researched questions, a community + member may be willing to help. 💬 + + + To increase the chance of a productive review: + + - Use [the template provided in the PR + description](https://github.com/matplotlib/matplotlib/blob/main/.github/PULL_REQUEST_TEMPLATE.md) + and fill it out as completely as possible, especially the summary and AI Disclosure sections. + + - Make sure your PR conforms to our [PR + checklist](https://matplotlib.org/devdocs/devel/pr_guide.html#summary-for-pull-request-authors). + + + As the author, you are responsible for driving this PR, which entails doing + necessary background research as well as presenting its context and your + thought process. If you are a new contributor, or do not know how to + fulfill these requirements, we recommend that you familiarize + yourself with Matplotlib's + [development conventions](https://matplotlib.org/devdocs/devel/index.html) + or engage with the community via our [Discourse](https://discourse.matplotlib.org/) + or one of our [meetings](https://scientific-python.org/calendars/) + before submitting code. + + + If you substantially improve this PR within two weeks, leave a comment + and a team member may remove the `status: autoclose candidate` label and the + PR stays open. Cosmetic changes or incomplete fixes will not be + sufficient. Maintainers will assess improvements on their own + schedule. Please do not ping (`@`) maintainers. diff --git a/.github/workflows/autoclose_schedule.yml b/.github/workflows/autoclose_schedule.yml new file mode 100644 index 000000000000..7e0fbd2055e9 --- /dev/null +++ b/.github/workflows/autoclose_schedule.yml @@ -0,0 +1,37 @@ +--- +name: autoclose schedule +# Autoclose PRs labeled with "status: autoclose candidate" after 2 weeks. +# Based on scikit-learn's implementation at +# https://github.com/scikit-learn/scikit-learn/blob/main/.github/workflows/autoclose-schedule.yml + +permissions: + contents: read + pull-requests: write + +on: + schedule: + - cron: '0 2 * * *' # runs daily at 02:00 UTC + workflow_dispatch: + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + + autoclose: + name: autoclose labeled PRs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.13' + - name: Install PyGithub + run: pip install -Uq PyGithub + + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Close PRs labeled more than 14 days ago + run: | + python tools/autoclose_prs.py diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml new file mode 100644 index 000000000000..2bb7f9544902 --- /dev/null +++ b/.github/workflows/cibuildwheel.yml @@ -0,0 +1,201 @@ +--- +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: {} + +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 + permissions: + contents: read + outputs: + SDIST_NAME: ${{ steps.sdist.outputs.SDIST_NAME }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + 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 }} + permissions: + contents: read + 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: "AMD64" + - os: windows-11-arm + cibw_archs: "ARM64" + - os: macos-15-intel + cibw_archs: "x86_64" + - os: macos-14 + cibw_archs: "arm64" + + steps: + - name: Download sdist + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: cibw-sdist + path: dist/ + + - name: Purge Strawberry Perl + if: startsWith(matrix.os, 'windows-') + run: Remove-Item -Recurse C:\Strawberry + + - name: Build wheels for CPython 3.14 + uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + with: + package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }} + env: + CIBW_BUILD: "cp314-* cp314t-*" + CIBW_ENABLE: "cpython-freethreading cpython-prerelease" + CIBW_ARCHS: ${{ matrix.cibw_archs }} + CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 + + - name: Build wheels for CPython 3.13 + uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + with: + package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }} + env: + CIBW_BUILD: "cp313-* cp313t-*" + CIBW_ENABLE: cpython-freethreading + CIBW_ARCHS: ${{ matrix.cibw_archs }} + + - name: Build wheels for CPython 3.12 + uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + 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@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + 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@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + with: + package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }} + env: + CIBW_BUILD: "pp311-*" + CIBW_ARCHS: ${{ matrix.cibw_archs }} + CIBW_ENABLE: pypy + if: matrix.cibw_archs != 'aarch64' && matrix.os != 'windows-latest' && matrix.os != 'windows-11-arm' + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: cibw-wheels-${{ runner.os }}-${{ matrix.cibw_archs }} + path: ./wheelhouse/*.whl + if-no-files-found: error diff --git a/.github/workflows/circleci.yml b/.github/workflows/circleci.yml new file mode 100644 index 000000000000..49dc4ea3b3ec --- /dev/null +++ b/.github/workflows/circleci.yml @@ -0,0 +1,78 @@ +--- +name: "CircleCI artifact handling" +on: [status] + +permissions: {} + +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@5d358ff96e96429a5c64a969bb4a574555439f4f # v1.3.1 + 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.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@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.5.0 + 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..75f6a451c7ee --- /dev/null +++ b/.github/workflows/clean_pr.yml @@ -0,0 +1,55 @@ +--- +name: PR cleanliness +on: [pull_request] + +permissions: {} + +jobs: + pr_clean: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.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..04609e6a868f --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,48 @@ +--- +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' + +permissions: {} + +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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Initialize CodeQL + uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 + 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@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 diff --git a/.github/workflows/conflictcheck.yml b/.github/workflows/conflictcheck.yml new file mode 100644 index 000000000000..2058da8ca9fb --- /dev/null +++ b/.github/workflows/conflictcheck.yml @@ -0,0 +1,26 @@ +--- +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] + +permissions: {} + +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..4b790ea52a7d --- /dev/null +++ b/.github/workflows/cygwin.yml @@ -0,0 +1,245 @@ +--- +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: {} + +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 + permissions: + contents: read + 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: cygwin/cygwin-install-action@711d29f3da23c9f4a1798e369a6f01198c13b11a # v6 + 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@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: C:\cygwin\home\runneradmin\.cache\pip + key: Cygwin-py3.${{ matrix.python-minor-version }}-pip-${{ hashFiles('pyproject.toml') }} + restore-keys: ${{ matrix.os }}-py3.${{ matrix.python-minor-version }}-pip- + + - name: Cache ccache + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + 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@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + 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 --group build 'numpy>=1.25,<1.26' + export PATH="/usr/local/bin:$PATH" + python -m pip install --upgrade --group test 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..0c263623942b --- /dev/null +++ b/.github/workflows/do_not_merge.yml @@ -0,0 +1,31 @@ +--- +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') || + contains(github.event.pull_request.labels.*.name, 'DO NOT MERGE') }} + 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" + echo "* DO NOT MERGE" + 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..6543f05a0837 --- /dev/null +++ b/.github/workflows/good-first-issue.yml @@ -0,0 +1,36 @@ +--- +name: Add comment on good first issues +on: + issues: + types: + - labeled + +permissions: {} + +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@e8674b075228eee787fea43ef493e45ece1004c9 # v5.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. This is a non-urgent task + intended for human contributors to learn how to contribute; therefore please + do not try to automate a solution using AI. 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..600e7fc34a95 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,17 @@ +--- +name: "Pull Request Labeler" +on: + - pull_request_target + +permissions: {} + +jobs: + labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0 + with: + sync-labels: true diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml new file mode 100644 index 000000000000..51593f607653 --- /dev/null +++ b/.github/workflows/linting.yml @@ -0,0 +1,104 @@ +--- +name: Linting +on: [pull_request] + +permissions: {} + +jobs: + pre-commit: + name: precommit + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: "3.x" + - uses: j178/prek-action@bdca6f102f98e2b4c7029491a53dfd366469e33d # v2.0.4 + with: + extra-args: --hook-stage manual --all-files + + ruff: + name: ruff + runs-on: ubuntu-latest + permissions: + contents: read + checks: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Set up Python 3 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.11' + + - name: Install ruff + run: pip3 install ruff + + - name: Set up reviewdog + uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.5.0 + + - 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: + contents: read + checks: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Set up Python 3 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.11' + + - name: Install mypy + run: pip3 install --group build --group typing + + - name: Set up reviewdog + uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.5.0 + + - 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: + contents: read + checks: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: eslint + uses: reviewdog/action-eslint@556a3fdaf8b4201d4d74d406013386aa4f7dab96 # v1.34.0 + with: + filter_mode: nofilter + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-check + workdir: 'lib/matplotlib/backends/web_backend/' diff --git a/.github/workflows/mypy-stubtest.yml b/.github/workflows/mypy-stubtest.yml new file mode 100644 index 000000000000..81fcd48462e8 --- /dev/null +++ b/.github/workflows/mypy-stubtest.yml @@ -0,0 +1,47 @@ +--- +name: Mypy Stubtest +on: [pull_request] + +permissions: {} + +jobs: + mypy-stubtest: + name: mypy-stubtest + runs-on: ubuntu-latest + permissions: + contents: read + checks: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Set up Python 3 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.11' + + - name: Set up reviewdog + uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.5.0 + + - 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..47d1de50781c --- /dev/null +++ b/.github/workflows/nightlies.yml @@ -0,0 +1,66 @@ +--- +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: {} + +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} + permissions: + actions: read + 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" + ARTIFACT_PATTERN="cibw-wheels-*" + + for WORKFLOW_NAME in cibuildwheel.yml wasm.yml; do + 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}" + done + + mkdir dist + mv ${ARTIFACT_PATTERN}/*.whl dist/ + ls -l dist/ + + - name: Upload wheels to Anaconda Cloud as nightlies + uses: scientific-python/upload-nightly-action@e76cfec8a4611fd02808a801b0ff5a7d7c1b2d99 # 0.6.4 + 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..48691e61d87b --- /dev/null +++ b/.github/workflows/pr_welcome.yml @@ -0,0 +1,51 @@ +--- +name: PR Greetings + +on: + pull_request_target: + types: opened + issues: + types: opened + +permissions: {} + +jobs: + greeting: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: plbstl/first-contribution@7c31f41b0e7a70adfcae06cf964679f61af6780b # v4.3.0 + with: + labels: first-contribution + pr-opened-msg: >+ + 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. We also ask that you please finish addressing + any review comments on this PR and wait for it to be merged (or + closed) before opening a new one, as it can be a valuable learning + experience to go through the review process. + + + You can also join us [on discourse + chat](https://discourse.matplotlib.org/chat/c/matplotlib/2) 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). + + **Please let us know if (and how) you use AI, it will help us give you + better feedback on your PR.** + + + 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). + issue-opened-msg: "" diff --git a/.github/workflows/stale-tidy.yml b/.github/workflows/stale-tidy.yml new file mode 100644 index 000000000000..feb1fe701d70 --- /dev/null +++ b/.github/workflows/stale-tidy.yml @@ -0,0 +1,28 @@ +--- +name: 'Close inactive issues' +on: + schedule: + - cron: '30 1 * * 2,4,6' + +permissions: {} + +jobs: + stale: + if: github.repository == 'matplotlib/matplotlib' + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.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,status: confirmed bug" + 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..63f1a1ce3b05 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,44 @@ +--- +name: 'Label inactive PRs' +on: + schedule: + - cron: '30 1 * * 1' + +permissions: {} + +jobs: + stale: + if: github.repository == 'matplotlib/matplotlib' + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.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" + sort-by: updated diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000000..a3a9def4bd40 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,433 @@ +--- +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: + +permissions: {} + +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 ci/minver-requirements.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: '--group test-extra' + # 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: ubuntu-24.04 + python-version: '3.14' + - os: ubuntu-24.04-arm + python-version: '3.12' + - os: macos-14 # This runner is on M1 (arm64) chips. + python-version: '3.11' + # 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.12' + # https://github.com/matplotlib/matplotlib/issues/29732 + pygobject-ver: '<3.52.0' + - os: macos-15 # This runner is on M1 (arm64) chips. + python-version: '3.13' + # https://github.com/matplotlib/matplotlib/issues/29732 + pygobject-ver: '<3.52.0' + - os: macos-15 # This runner is on M1 (arm64) chips. + python-version: '3.14' + # https://github.com/matplotlib/matplotlib/issues/29732 + pygobject-ver: '<3.52.0' + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.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 \ + gir1.2-gtk-4.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 ]]; then + sudo apt-get install -yy --no-install-recommends \ + 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@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + if: startsWith(runner.os, 'Linux') + with: + path: ~/.cache/pip + key: | + ${{ matrix.os }}-py${{ matrix.python-version }}-pip-${{ + hashFiles('pyproject.toml', 'ci/minver-requirements.txt') }} + restore-keys: | + ${{ matrix.os }}-py${{ matrix.python-version }}-pip- + - name: Cache pip + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + if: startsWith(runner.os, 'macOS') + with: + path: ~/Library/Caches/pip + key: ${{ matrix.os }}-py${{ matrix.python-version }}-pip-${{ hashFiles('pyproject.toml') }} + restore-keys: | + ${{ matrix.os }}-py${{ matrix.python-version }}-pip- + - name: Cache ccache + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + 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@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + 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 --prefer-binary \ + --group build --group test ${{ 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-24.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.11' + ]]; 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 pandas + + - 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: | + find ./result_images -name "*-expected*.png" | while read file; do + if [[ $file == *-expected_???.png ]]; then + extension=${file: -7:3} + base=${file%*-expected_$extension.png}_$extension + else + extension="png" + base=${file%-expected.png} + fi + if [[ ! -e ${base}-failed-diff.png ]]; then + indent="" + list=($file $base.png) + if [[ $extension != "png" ]]; then + list+=(${base%_$extension}-expected.$extension ${base%_$extension}.$extension) + fi + for to_remove in "${list[@]}"; do + if [[ -e $to_remove ]]; then + rm $to_remove + echo "${indent}Removed $to_remove" + fi + indent+=" " + done + fi + done + + 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 || "${{ matrix.os }}" = ubuntu-24.04-arm ]]; then + # filter mismatch errors detected by lcov 2.x + LCOV_IGNORE_ERRORS='mismatch' + fi + lcov --rc lcov_branch_coverage=1 --ignore-errors $LCOV_IGNORE_ERRORS \ + --capture --directory . --exclude $PWD/subprojects --exclude $PWD/build \ + --output-file coverage.info + lcov --rc lcov_branch_coverage=1 --ignore-errors $LCOV_IGNORE_ERRORS \ + --output-file coverage.info --extract coverage.info $PWD/src/'*' + 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@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 + with: + name: "${{ matrix.python-version }} ${{ matrix.os }} ${{ matrix.name-suffix }}" + token: ${{ secrets.CODECOV_TOKEN }} + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + 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@3188c6ce06249206709d3b1f274d0d4c5a521601 # v3.4.5 + 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/.github/workflows/triage_board.yml b/.github/workflows/triage_board.yml new file mode 100644 index 000000000000..3ef26369afeb --- /dev/null +++ b/.github/workflows/triage_board.yml @@ -0,0 +1,24 @@ +--- +name: 'Update PR Triage Board' + +on: + schedule: + - cron: '0 * * * *' # Run every hour + workflow_dispatch: + +permissions: {} + +jobs: + pr-triage: + if: github.repository == 'matplotlib/matplotlib' + runs-on: ubuntu-latest + steps: + - name: Update PR Triage Board + uses: jupyter/pr-triage-board-bot@dae1209c73e70224b2f2955590d0698832a5a076 # main @ Oct 26, 2025 + with: + organization: 'matplotlib' + project-number: '11' + gh-app-id: '3339145' + gh-app-installation-id: '122963236' + gh-app-private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} + repositories: 'matplotlib' diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml new file mode 100644 index 000000000000..e1668d99af60 --- /dev/null +++ b/.github/workflows/wasm.yml @@ -0,0 +1,63 @@ +--- +name: Build wasm 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_wasm: + if: >- + ( + 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 wasm + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + name: Install Python + with: + python-version: '3.13' + + - name: Build wheels for wasm + uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + env: + CIBW_BUILD: "cp312-*" + CIBW_PLATFORM: "pyodide" + CIBW_TEST_COMMAND: "true" + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: cibw-wheels-wasm + path: ./wheelhouse/*.whl + if-no-files-found: error diff --git a/.gitignore b/.gitignore index b56c466ef4e3..0460152a792f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,9 @@ *.kdev4 .project .pydevproject -.swp +*.swp +.idea +.vscode/ # Compiled source # ################### @@ -27,16 +29,23 @@ # 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/.* +!subprojects/packagefiles/ # OS generated files # ###################### @@ -49,21 +58,74 @@ 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 + +# uv files # +############ +uv.lock + +# 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..bbadcb8ff879 100644 --- a/.mailmap +++ b/.mailmap @@ -1,36 +1,323 @@ -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 + +Andreas C Mueller Andreas Mueller + +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 + +CharlesHe16 + +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 + +Diego Leal Petrola + +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 + +Hannes Breytenbach + +Hans Moritz Günther + +Harshal Prakash Patankar + +Harshit Patni + +Harutaka Kawamura + +Hood Chatham Hood + +Ian Hunt-Isaak + +ImportanceOfBeingErnest + +J. Goutin JGoutin + +Jakub Klus <48711526+deep-jkl@users.noreply.github.com> + +Jack Kelly +Jack Kelly + +Jaime Fernandez + +Jake Vanderplas +Jake Vanderplas +Jake Vanderplas + +James R. Evans + +Jan-Hendrik Müller <44469195+kolibril13@users.noreply.github.com> + +Jeff Lutgen + +Jeffrey Bingham + +Jens Hedegaard Nielsen +Jens Hedegaard Nielsen + +Jerome F. Villegas + +Joel Frederico <458871+joelfrederico@users.noreply.github.com> + +Johan von Forstner + +John Hunter + +Jorrit Wronski + +Jose Manuel Martí + +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 + +luz paz + +Manan Kevadiya +Manan Kevadiya <43081866+manan2501@users.noreply.github.com> + +Manuel Nuno Melo + +Marat Kopytjuk + +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 + +Péter Leéh + +Peter Würtz +Peter Würtz + +Phil Elson +Phil Elson +Phil Elson + +Philipp Nagel + +productivememberofsociety666 none + +Rishikesh + +Ruth Nainggolan Ruth G. N <32371319+ruthgn@users.noreply.github.com> + +RyanPan + +Richard Sheridan + +Samesh Lakhotia +Samesh Lakhotia <43701530+sameshl@users.noreply.github.com> ' + +Scott Lasley + +Sebastian Raschka +Sebastian Raschka + +ShawnChen1996 + +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 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..4602570328a9 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,122 @@ +--- +ci: + autofix_prs: false + autoupdate_schedule: 'quarterly' +exclude: | + (?x)^( + extern| + subprojects/packagefiles| + LICENSE| + lib/matplotlib/mpl-data| + doc/devel/gitwash| + doc/release/prev| + doc/api/prev| + lib/matplotlib/tests/data/tinypages + ) +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.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: [diff, 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: [diff, svg] + - repo: https://github.com/pre-commit/mirrors-mypy + rev: fc0f09a29bb495f4a91f00266155d6282d52485d # frozen: v1.20.2 + 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: 6fec9b7edb08fd9989088709d864a7826dc74e80 # frozen: v0.15.12 + hooks: + # Run the linter. + - id: ruff-check + args: [--fix, --show-fixes] + - repo: https://github.com/codespell-project/codespell + rev: 2ccb47ff45ad361a21071a7eedda4c37e6ae8c5a # frozen: v2.4.2 + 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: a333737ed43df02b18e6c95477ea1b285b3de15a # frozen: 8.0.1 + hooks: + - id: isort + name: isort (python) + files: ^galleries/tutorials/|^galleries/examples/|^galleries/plot_types/ + - repo: https://github.com/rstcheck/rstcheck + rev: 77490ffa33bfc0928975ae3cf904219903db755d # frozen: v6.2.5 + hooks: + - id: rstcheck + additional_dependencies: + - rstcheck-core!=1.3 # https://github.com/rstcheck/rstcheck-core/pull/114#pullrequestreview-4239740896 + - sphinx>=1.8.1 + - tomli + - repo: https://github.com/adrienverge/yamllint + rev: cba56bcde1fdd01c1deb3f945e69764c291a6530 # frozen: v1.38.0 + hooks: + - id: yamllint + args: ["--strict", "--config-file=.yamllint.yml"] + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 13614ab716a3113145f1294ed259d9fbe5678ff3 # frozen: 0.37.1 + 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 fa968ff92c62..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,121 +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= - - secure: "dfjNqGKzQG5bu3FnDNwLG8H/C4QoieFo4PfFmZPdM2RY7WIzukwKFNT6kiDfOrpwt+2bR7FhzjOGlDECGtlGOtYPN8XuXGjhcP4a4IfakdbDfF+D3NPIpf5VlE6776k0VpvcZBTMYJKNFIMc7QPkOwjvNJ2aXyfe3hBuGlKJzQU=" - - 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 sphinx==1.2.3 - - sudo apt-get update && sudo apt-get -qq install inkscape libav-tools gdb mencoder - # We use --no-install-recommends to avoid pulling in additional large latex docs that we don't need - - # We manually install humor sans using the package from Ubuntu 14.10. Unfortunatly humor sans is not - # availible in the Ubuntu version used by Travis but we can manually install the deb from a later - # version since is it basically just a .ttf file - - # We install ipython to use the console highlighting. From IPython 3 this depends on jsonschema and misture. - # Neihter is installed as a dependency of IPython since they are not used by the IPython console. - - | - if [[ $BUILD_DOCS == true ]]; then - sudo apt-get install -qq --no-install-recommends dvipng texlive-latex-base texlive-latex-extra texlive-fonts-recommended graphviz - pip install numpydoc linkchecker ipython jsonschema mistune - wget http://mirrors.kernel.org/ubuntu/pool/universe/f/fonts-humor-sans/fonts-humor-sans_1.0-1_all.deb - sudo dpkg -i fonts-humor-sans_1.0-1_all.deb - wget https://googlefontdirectory.googlecode.com/hg/ofl/felipa/Felipa-Regular.ttf - sudo cp Felipa-Regular.ttf /usr/local/share/fonts/ - fc-cache -f -v - 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 # needed for pep8-conformance test of the examples - mkdir ../tmp_test_dir - cd ../tmp_test_dir - gdb -return-child-result -batch -ex r -ex bt --args python ../matplotlib/tests.py -sv --processes=8 --process-timeout=300 $TEST_ARGS - else - cd doc - python make.py html --small --warningsaserrors - # We don't build the LaTeX docs here, so linkchecker will complain - touch build/html/Matplotlib.pdf - linkchecker build/html/index.html - fi - -after_failure: - | - if [[ $BUILD_DOCS == false && $TRAVIS_PULL_REQUEST == false && $TRAVIS_REPO_SLUG == 'matplotlib/matplotlib' ]]; then - gem install travis-artifacts - cd $TRAVIS_BUILD_DIR/../tmp_test_dir - tar cjf result_images.tar.bz2 result_images - travis-artifacts upload --path result_images.tar.bz2 - 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 - -after_success: - | - if [[ $TRAVIS_PULL_REQUEST == false && $BUILD_DOCS == true && $TRAVIS_BRANCH == 'master' ]]; then - cd $TRAVIS_BUILD_DIR - echo "Uploading documentation" - openssl aes-256-cbc -K $encrypted_cc802e084cd0_key -iv $encrypted_cc802e084cd0_iv -in .travis/matplotlibDeployKey.enc -out .travis/matplotlibDeployKey -d - eval `ssh-agent -s` - chmod 600 .travis/matplotlibDeployKey - ssh-add .travis/matplotlibDeployKey - cd .. - git clone git@github.com:matplotlib/devdocs.git - cd devdocs - git checkout --orphan gh-pages - git reset --hard first_commit - cp -R ../matplotlib/doc/build/html/. . - touch .nojekyll - git config --global user.email "MatplotlibTravisBot@nomail" - git config --global user.name "MatplotlibTravisBot" - git config --global push.default simple - git add . - git commit -m "Docs build of $TRAVIS_COMMIT" - git push --set-upstream origin gh-pages --force - else - echo "Will only deploy docs build from matplotlib master branch" - fi - if [[ $TRAVIS_PULL_REQUEST == false ]] && \ - [[ $TRAVIS_REPO_SLUG == 'matplotlib/matplotlib' ]] && \ - [[ $TRAVIS_BRANCH == 'master' ]]; then - cd $TRAVIS_BUILD_DIR - python .travis/travis_after_all.py - export $(cat .to_export_back) - if [ "$BUILD_LEADER" = "YES" ]; then - if [ "$BUILD_AGGREGATE_STATUS" = "others_succeeded" ]; then - echo "All Succeeded! Triggering OSX build..." - ./.travis/build_children.sh - else - echo "Some Failed; no OSX build" - fi - fi - fi diff --git a/.travis/build_children.sh b/.travis/build_children.sh deleted file mode 100755 index 5f26c4890cc1..000000000000 --- a/.travis/build_children.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# Modified from: -# https://github.com/ajdm/travis-build-children/blob/master/build_children.sh - -# Get last child project build number from branch named "latest" -BUILD_NUM=$(curl -s 'https://api.travis-ci.org/repos/MacPython/matplotlib-wheels/branches/latest' | grep -o '^{"branch":{"id":[0-9]*,' | grep -o '[0-9]' | tr -d '\n') - -# Restart last child project build -curl -X POST https://api.travis-ci.org/builds/$BUILD_NUM/restart --header "Authorization: token "$AUTH_TOKEN diff --git a/.travis/matplotlibDeployKey.enc b/.travis/matplotlibDeployKey.enc deleted file mode 100644 index f73fb807cdf5..000000000000 Binary files a/.travis/matplotlibDeployKey.enc and /dev/null differ diff --git a/.travis/travis_after_all.py b/.travis/travis_after_all.py deleted file mode 100644 index 4e35b39ab9a5..000000000000 --- a/.travis/travis_after_all.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copied from: -# https://github.com/dmakhno/travis_after_all -# commit b7172bca9 -import os -import json -import time -import logging - -try: - import urllib.request as urllib2 -except ImportError: - import urllib2 - -log = logging.getLogger("travis.leader") -log.addHandler(logging.StreamHandler()) -log.setLevel(logging.INFO) - -TRAVIS_JOB_NUMBER = 'TRAVIS_JOB_NUMBER' -TRAVIS_BUILD_ID = 'TRAVIS_BUILD_ID' -POLLING_INTERVAL = 'LEADER_POLLING_INTERVAL' - -build_id = os.getenv(TRAVIS_BUILD_ID) -polling_interval = int(os.getenv(POLLING_INTERVAL, '5')) - -#assume, first job is the leader -is_leader = lambda job_number: job_number.endswith('.1') - -if not os.getenv(TRAVIS_JOB_NUMBER): - # seems even for builds with only one job, this won't get here - log.fatal("Don't use defining leader for build without matrix") - exit(1) -elif is_leader(os.getenv(TRAVIS_JOB_NUMBER)): - log.info("This is a leader") -else: - #since python is subprocess, env variables are exported back via file - with open(".to_export_back", "w") as export_var: - export_var.write("BUILD_MINION=YES") - log.info("This is a minion") - exit(0) - - -class MatrixElement(object): - def __init__(self, json_raw): - self.is_finished = json_raw['finished_at'] is not None - self.is_succeeded = json_raw['result'] == 0 - self.number = json_raw['number'] - self.is_leader = is_leader(self.number) - - -def matrix_snapshot(): - """ - :return: Matrix List - """ - response = urllib2.build_opener().open("https://api.travis-ci.org/builds/{0}".format(build_id)).read() - raw_json = json.loads(response) - matrix_without_leader = [MatrixElement(element) for element in raw_json["matrix"]] - return matrix_without_leader - - -def wait_others_to_finish(): - def others_finished(): - """ - Dumps others to finish - Leader cannot finish, it is working now - :return: tuple(True or False, List of not finished jobs) - """ - snapshot = matrix_snapshot() - finished = [el.is_finished for el in snapshot if not el.is_leader] - return reduce(lambda a, b: a and b, finished), [el.number for el in snapshot if - not el.is_leader and not el.is_finished] - - while True: - finished, waiting_list = others_finished() - if finished: break - log.info("Leader waits for minions {0}...".format(waiting_list)) # just in case do not get "silence timeout" - time.sleep(polling_interval) - - -try: - wait_others_to_finish() - - final_snapshot = matrix_snapshot() - log.info("Final Results: {0}".format([(e.number, e.is_succeeded) for e in final_snapshot])) - - BUILD_AGGREGATE_STATUS = 'BUILD_AGGREGATE_STATUS' - others_snapshot = [el for el in final_snapshot if not el.is_leader] - if reduce(lambda a, b: a and b, [e.is_succeeded for e in others_snapshot]): - os.environ[BUILD_AGGREGATE_STATUS] = "others_succeeded" - elif reduce(lambda a, b: a and b, [not e.is_succeeded for e in others_snapshot]): - log.error("Others Failed") - os.environ[BUILD_AGGREGATE_STATUS] = "others_failed" - else: - log.warn("Others Unknown") - os.environ[BUILD_AGGREGATE_STATUS] = "unknown" - #since python is subprocess, env variables are exported back via file - with open(".to_export_back", "w") as export_var: - export_var.write("BUILD_LEADER=YES {0}={1}".format(BUILD_AGGREGATE_STATUS, os.environ[BUILD_AGGREGATE_STATUS])) - -except Exception as e: - log.fatal(e) 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 506d5ed307a7..000000000000 --- a/CHANGELOG +++ /dev/null @@ -1,5390 +0,0 @@ -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 `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 - 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 69f500684a0c..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_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_FREETYPE b/LICENSE/LICENSE_FREETYPE new file mode 100644 index 000000000000..8b9ce9e2e6e3 --- /dev/null +++ b/LICENSE/LICENSE_FREETYPE @@ -0,0 +1,46 @@ +FREETYPE LICENSES +----------------- + +The FreeType 2 font engine is copyrighted work and cannot be used +legally without a software license. In order to make this project +usable to a vast majority of developers, we distribute it under two +mutually exclusive open-source licenses. + +This means that *you* must choose *one* of the two licenses described +below, then obey all its terms and conditions when using FreeType 2 in +any of your projects or products. + + - The FreeType License, found in the file `docs/FTL.TXT`, which is + similar to the original BSD license *with* an advertising clause + that forces you to explicitly cite the FreeType project in your + product's documentation. All details are in the license file. + This license is suited to products which don't use the GNU General + Public License. + + Note that this license is compatible to the GNU General Public + License version 3, but not version 2. + + - The GNU General Public License version 2, found in + `docs/GPLv2.TXT` (any later version can be used also), for + programs which already use the GPL. Note that the FTL is + incompatible with GPLv2 due to its advertisement clause. + +The contributed BDF and PCF drivers come with a license similar to +that of the X Window System. It is compatible to the above two +licenses (see files `src/bdf/README` and `src/pcf/README`). The same +holds for the source code files `src/base/fthash.c` and +`include/freetype/internal/fthash.h`; they were part of the BDF driver +in earlier FreeType versions. + +The gzip module uses the zlib license (see `src/gzip/zlib.h`) which +too is compatible to the above two licenses. + +The files `src/autofit/ft-hb.c` and `src/autofit/ft-hb.h` contain code +taken almost verbatim from the HarfBuzz file `hb-ft.cc`, which uses +the 'Old MIT' license, compatible to the above two licenses. + +The MD5 checksum support (only used for debugging in development +builds) is in the public domain. + + +--- end of LICENSE.TXT --- diff --git a/LICENSE/LICENSE_HARFBUZZ b/LICENSE/LICENSE_HARFBUZZ new file mode 100644 index 000000000000..1dd917e9f2e7 --- /dev/null +++ b/LICENSE/LICENSE_HARFBUZZ @@ -0,0 +1,42 @@ +HarfBuzz is licensed under the so-called "Old MIT" license. Details follow. +For parts of HarfBuzz that are licensed under different licenses see individual +files names COPYING in subdirectories where applicable. + +Copyright © 2010-2022 Google, Inc. +Copyright © 2015-2020 Ebrahim Byagowi +Copyright © 2019,2020 Facebook, Inc. +Copyright © 2012,2015 Mozilla Foundation +Copyright © 2011 Codethink Limited +Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies) +Copyright © 2009 Keith Stribley +Copyright © 2011 Martin Hosken and SIL International +Copyright © 2007 Chris Wilson +Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod +Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc. +Copyright © 1998-2005 David Turner and Werner Lemberg +Copyright © 2016 Igalia S.L. +Copyright © 2022 Matthias Clasen +Copyright © 2018,2021 Khaled Hosny +Copyright © 2018,2019,2020 Adobe, Inc +Copyright © 2013-2015 Alexei Podtelezhnikov + +For full copyright notices consult the individual files in the package. + + +Permission is hereby granted, without written agreement and without +license or royalty fees, to use, copy, modify, and distribute this +software and its documentation for any purpose, provided that the +above copyright notice and the following two paragraphs appear in +all copies of this software. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN +IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 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_LIBRAQM b/LICENSE/LICENSE_LIBRAQM new file mode 100644 index 000000000000..97e2489b7798 --- /dev/null +++ b/LICENSE/LICENSE_LIBRAQM @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright © 2015 Information Technology Authority (ITA) +Copyright © 2016-2023 Khaled Hosny + +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_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_SHEENBIDI b/LICENSE/LICENSE_SHEENBIDI new file mode 100755 index 000000000000..d64569567334 --- /dev/null +++ b/LICENSE/LICENSE_SHEENBIDI @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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 + + http://www.apache.org/licenses/LICENSE-2.0 + + 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. 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..bbbbec35331e --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +[![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) +[![LFX Health Score](https://insights.linuxfoundation.org/api/badge/health-score?project=matplotlib)](https://insights.linuxfoundation.org/project/matplotlib) + +[![Discourse help forum](https://img.shields.io/badge/help_forum-discourse-blue.svg)](https://discourse.matplotlib.org) +[![Discourse chat](https://img.shields.io/badge/chat-discourse-mediumaquamarine)](https://discourse.matplotlib.org/chat/c/matplotlib/2) +[![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/stable/_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/stable/_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: + +[Discourse Chat](https://discourse.matplotlib.org/chat/c/matplotlib/2) 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..829a1c7b9005 --- /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 --group build + python -m pip install --prefer-binary --group test --group test-extra + 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 4136dae102a3..000000000000 --- a/boilerplate.py +++ /dev/null @@ -1,329 +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..e138f26e216a --- /dev/null +++ b/ci/codespell-ignore-words.txt @@ -0,0 +1,23 @@ +aas +ABD +axises +coo +curvelinear +filll +flate +fpt +hax +inh +inout +ment +nd +oint +oly +te +thisy +ure +whis +wit +Copin +socio-economic +Ines 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/minver-requirements.txt b/ci/minver-requirements.txt new file mode 100644 index 000000000000..3b6aea9e7ca3 --- /dev/null +++ b/ci/minver-requirements.txt @@ -0,0 +1,23 @@ +# Extra pip requirements for the minimum-version CI run + +contourpy==1.0.1 +cycler==0.10 +fonttools==4.22.0 +importlib-resources==3.2.0 +kiwisolver==1.3.2 +meson-python==0.13.2 +meson==1.1.0 +numpy==1.25.0 +packaging==20.0 +pillow==9.0.1 +pyparsing==3.0.0 +pytest==7.0.0 +python-dateutil==2.7 + +# Test ipython/matplotlib-inline before backend mapping moved to mpl. +# This should be tested for a reasonably long transition period, +# but we will eventually remove the test when we no longer support +# ipython/matplotlib-inline versions from before the transition. +ipython==7.29.0 +ipykernel==5.5.6 +matplotlib-inline<0.1.7 diff --git a/ci/mypy-stubtest-allowlist.txt b/ci/mypy-stubtest-allowlist.txt new file mode 100644 index 000000000000..0e199889cb07 --- /dev/null +++ b/ci/mypy-stubtest-allowlist.txt @@ -0,0 +1,58 @@ +# 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\.ft2font\.LayoutItem +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__ + +# 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__ + +# only defined in stubs; not present at runtime +matplotlib\.animation\.EventSourceProtocol + +# Avoid a regression in NewType handling for stubtest +# https://github.com/python/mypy/issues/19877 +matplotlib\.ft2font\.GlyphIndexType\.__init__ 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..fb1e821778c3 --- /dev/null +++ b/ci/schemas/conda-environment.json @@ -0,0 +1,53 @@ +{ + "title": "conda environment file", + "description": "Support for conda's environment.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 a4ba3a698df6..000000000000 --- a/distribute_setup.py +++ /dev/null @@ -1,559 +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..d32a029fe05d --- /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/canvasagg.png b/doc/_static/canvasagg.png new file mode 100644 index 000000000000..2255274d3011 Binary files /dev/null and b/doc/_static/canvasagg.png 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/embedding_in_qt.png b/doc/_static/embedding_in_qt.png new file mode 100644 index 000000000000..b4a5dc9ae038 Binary files /dev/null and b/doc/_static/embedding_in_qt.png differ diff --git a/doc/_static/embedding_in_tk.png b/doc/_static/embedding_in_tk.png new file mode 100644 index 000000000000..25117aaf4b95 Binary files /dev/null and b/doc/_static/embedding_in_tk.png differ diff --git a/doc/_static/embedding_webagg.png b/doc/_static/embedding_webagg.png new file mode 100644 index 000000000000..2ad318ce6822 Binary files /dev/null and b/doc/_static/embedding_webagg.png 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/image.svg b/doc/_static/image.svg new file mode 100644 index 000000000000..c101e6aea399 --- /dev/null +++ b/doc/_static/image.svg @@ -0,0 +1,381 @@ + + + + + + + + 2026-04-26T10:16:40.198456 + image/svg+xml + + + Matplotlib v3.11.0.dev2285+ge1329a5eb.d20260419, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/multipage_pdf_thumbnail.svg b/doc/_static/multipage_pdf_thumbnail.svg new file mode 100644 index 000000000000..864c4c647492 --- /dev/null +++ b/doc/_static/multipage_pdf_thumbnail.svg @@ -0,0 +1,12 @@ + + + + + + + + + + Multipage + PDF + 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/scatter.svg b/doc/_static/scatter.svg new file mode 100644 index 000000000000..6db3c159c093 --- /dev/null +++ b/doc/_static/scatter.svg @@ -0,0 +1,591 @@ + + + + + + + + 2026-04-26T10:16:39.958872 + image/svg+xml + + + Matplotlib v3.11.0.dev2285+ge1329a5eb.d20260419, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/svg_histogram.svg b/doc/_static/svg_histogram.svg new file mode 100644 index 000000000000..9e9df77aef15 --- /dev/null +++ b/doc/_static/svg_histogram.svg @@ -0,0 +1,301 @@ + + + + + + 2026-03-25T12:33:41.331892 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + −3 + + + + + + + + + + −2 + + + + + + + + + + −1 + + + + + + + + + + 0 + + + + + + + + + + 1 + + + + + + + + + + 2 + + + + + + + + + + 3 + + + + + + + + + + + + + + + 0 + + + + + + + + + + 5 + + + + + + + + + + 10 + + + + + + + + + + 15 + + + + + + + + + + 20 + + + + + + + + + + 25 + + + + + + + + + + + + + + + + + From a web browser, click on the legend + marker to toggle the corresponding histogram. + + + + + + + Rabbits + + + + + + Frogs + + + + + + + + + + \ No newline at end of file diff --git a/doc/_static/svg_tooltip.svg b/doc/_static/svg_tooltip.svg new file mode 100644 index 000000000000..dd11c2d7782e --- /dev/null +++ b/doc/_static/svg_tooltip.svg @@ -0,0 +1,385 @@ + + + + + + 2026-03-25T12:36:20.674869 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/_static/switcher.json b/doc/_static/switcher.json new file mode 100644 index 000000000000..cc275467efc4 --- /dev/null +++ b/doc/_static/switcher.json @@ -0,0 +1,53 @@ +[ + { + "name": "3.10 (stable)", + "version": "3.10.9", + "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/toolmanager.png b/doc/_static/toolmanager.png new file mode 100644 index 000000000000..14aeba48995d Binary files /dev/null and b/doc/_static/toolmanager.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/14940554.svg b/doc/_static/zenodo_cache/14940554.svg new file mode 100644 index 000000000000..6e7d5c37bf7b --- /dev/null +++ b/doc/_static/zenodo_cache/14940554.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.14940554 + + + 10.5281/zenodo.14940554 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/15375714.svg b/doc/_static/zenodo_cache/15375714.svg new file mode 100644 index 000000000000..d5e403138561 --- /dev/null +++ b/doc/_static/zenodo_cache/15375714.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.15375714 + + + 10.5281/zenodo.15375714 + + + \ 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/16644850.svg b/doc/_static/zenodo_cache/16644850.svg new file mode 100644 index 000000000000..89910032da4e --- /dev/null +++ b/doc/_static/zenodo_cache/16644850.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.16644850 + + + 10.5281/zenodo.16644850 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/16999430.svg b/doc/_static/zenodo_cache/16999430.svg new file mode 100644 index 000000000000..44c448643e91 --- /dev/null +++ b/doc/_static/zenodo_cache/16999430.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.16999430 + + + 10.5281/zenodo.16999430 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/17298696.svg b/doc/_static/zenodo_cache/17298696.svg new file mode 100644 index 000000000000..9aa8d7c94349 --- /dev/null +++ b/doc/_static/zenodo_cache/17298696.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.17298696 + + + 10.5281/zenodo.17298696 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/17595503.svg b/doc/_static/zenodo_cache/17595503.svg new file mode 100644 index 000000000000..891bd118d125 --- /dev/null +++ b/doc/_static/zenodo_cache/17595503.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.17595503 + + + 10.5281/zenodo.17595503 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/19716234.svg b/doc/_static/zenodo_cache/19716234.svg new file mode 100644 index 000000000000..910ecbef7fae --- /dev/null +++ b/doc/_static/zenodo_cache/19716234.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.19716234 + + + 10.5281/zenodo.19716234 + + + \ 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/_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/2014-11-19_remove_set_graylevel.rst b/doc/api/api_changes/2014-11-19_remove_set_graylevel.rst deleted file mode 100644 index b346a227c7c2..000000000000 --- a/doc/api/api_changes/2014-11-19_remove_set_graylevel.rst +++ /dev/null @@ -1,6 +0,0 @@ -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. diff --git a/doc/api/api_changes/2014-12-12_axes_property.rst b/doc/api/api_changes/2014-12-12_axes_property.rst deleted file mode 100644 index 3e98a5cbd4a5..000000000000 --- a/doc/api/api_changes/2014-12-12_axes_property.rst +++ /dev/null @@ -1,16 +0,0 @@ -Prevent moving artists between Axes, Property-ify Artist.axes, deprecate Artist.{get,set}_axes -`````````````````````````````````````````````````````````````````````````````````````````````` - -The reason this was done was to prevent adding an Artist that is -already associated with an Axes to be 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 {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). diff --git a/doc/api/api_changes/2014-12-28_quiver.rst b/doc/api/api_changes/2014-12-28_quiver.rst deleted file mode 100644 index 98fc5aed97f5..000000000000 --- a/doc/api/api_changes/2014-12-28_quiver.rst +++ /dev/null @@ -1,12 +0,0 @@ -Tighted 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' kwarg in -the `Quiver.__init__` (and hence `Axes.quiver` and -`plt.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.__init__`. diff --git a/doc/api/api_changes/2015-02-19-IMT.rst b/doc/api/api_changes/2015-02-19-IMT.rst deleted file mode 100644 index 86a6033eb620..000000000000 --- a/doc/api/api_changes/2015-02-19-IMT.rst +++ /dev/null @@ -1,25 +0,0 @@ -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 rcParam `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 -http://matplotlib.org/examples/pylab_examples/contour_corner_mask.py -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. diff --git a/doc/api/api_changes/2015-03-03-LEO.rst b/doc/api/api_changes/2015-03-03-LEO.rst deleted file mode 100755 index 270affdf33ed..000000000000 --- a/doc/api/api_changes/2015-03-03-LEO.rst +++ /dev/null @@ -1,21 +0,0 @@ -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 throw 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 subtype 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, all Locator instances will not throw an AttributeError -when set_param() is called. For Locators that do not implement set_params(), -the default implementation in Locator is used. 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/api_changes/code_removal.rst b/doc/api/api_changes/code_removal.rst deleted file mode 100644 index eec6a5ea6c65..000000000000 --- a/doc/api/api_changes/code_removal.rst +++ /dev/null @@ -1,95 +0,0 @@ -Code Removal -```````````` - -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 coupled 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. - - -spinxext.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 ``set_colorbar`` method from ``ScalarMappable`` ------------------------------------------------------- -Remove ``set_colorbar`` method, use `colorbar` attribute directly. - - -patheffects.svg ---------------- - - remove ``get_proxy_renderer`` method from ``AbstarctPathEffect`` 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 - - -Remove ``faceted`` kwarg from scatter -------------------------------------- - -Remove support for the ``faceted`` kwarg. This was deprecated in -d48b34288e9651ff95c3b8a071ef5ac5cf50bae7 (2008-04-18!) and replaced by -``edgecolor``. diff --git a/doc/api/artist_api.rst b/doc/api/artist_api.rst index c8e38f88a6ca..f256d2b7164e 100644 --- a/doc/api/artist_api.rst +++ b/doc/api/artist_api.rst @@ -1,17 +1,203 @@ .. _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 + Artist.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..1f5f3e403bee 100644 --- a/doc/api/axes_api.rst +++ b/doc/api/axes_api.rst @@ -1,12 +1,636 @@ -**** -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.pie_label + + 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 + +.. _axes-api-adding-artists: + +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.get_figure + Axes.figure + 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..8476ab14cb86 100644 --- a/doc/api/cm_api.rst +++ b/doc/api/cm_api.rst @@ -1,11 +1,26 @@ -************* -cm (colormap) -************* - -:mod:`matplotlib.cm` -==================== +***************** +``matplotlib.cm`` +***************** .. automodule:: matplotlib.cm :members: :undoc-members: :show-inheritance: + +.. class:: ScalarMappable(colorizer, **kwargs) + :canonical: matplotlib.colorizer._ScalarMappable + + .. automethod:: autoscale + .. automethod:: autoscale_None + .. automethod:: changed + .. autoproperty:: colorbar + .. automethod:: get_alpha + .. automethod:: get_array + .. automethod:: get_clim + .. automethod:: get_cmap + .. autoproperty:: norm + .. automethod:: set_array + .. automethod:: set_clim + .. automethod:: set_cmap + .. automethod:: set_norm + .. automethod:: to_rgba 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..18e7c43932a9 100644 --- a/doc/api/colors_api.rst +++ b/doc/api/colors_api.rst @@ -1,15 +1,100 @@ -****** -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 + + Norm + Normalize + NoNorm + AsinhNorm + BoundaryNorm + CenteredNorm + FuncNorm + LogNorm + PowerNorm + SymLogNorm + TwoSlopeNorm + MultiNorm + +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 02ee4f9d1e6c..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,14 +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..b2fafc08e5fc 100644 --- a/doc/api/matplotlib_configuration_api.rst +++ b/doc/api/matplotlib_configuration_api.rst @@ -1,37 +1,91 @@ -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 -.. py:data:: rcParams +.. autofunction:: interactive - An instance of :class:`RcParams` for handling default matplotlib values. +.. autofunction:: is_interactive -.. autofunction:: rc +Default values and styling +========================== -.. autofunction::rcdefaults +.. py:data:: rcParams + :type: RcParams -.. autofunction::rc_file + The global configuration settings for Matplotlib. -.. autofunction::rc_context + This is a dictionary-like variable that stores the current configuration + settings. Many of the values control styling, but others control + various aspects of Matplotlib's behavior. -.. autofunction:: matplotlib_fname + See :doc:`/users/explain/configuration` for a full list of config + parameters. -.. autofunction::rc_file_defaults + See :ref:`customizing` for usage information. -.. autofunction::interactive + Notes + ----- + This object is also available as ``plt.rcParams`` via the + `matplotlib.pyplot` module (which by convention is imported as ``plt``). -.. autofunction::is_interactive .. autoclass:: RcParams + :no-members: + + .. automethod:: find_all + .. automethod:: copy + +.. autofunction:: rc_context + +.. autofunction:: rc + +.. autofunction:: rcdefaults + +.. autofunction:: rc_file_defaults + +.. autofunction:: rc_file .. autofunction:: rc_params .. autofunction:: rc_params_from_file -.. autoclass:: rc_context +.. autofunction:: get_configdir + +.. autofunction:: matplotlib_fname + +.. autofunction:: get_data_path + +Logging +======= + +.. autofunction:: set_loglevel + +Colormaps and color sequences +============================= + +.. autodata:: colormaps + :no-value: + +.. autodata:: color_sequences + :no-value: + +Miscellaneous +============= + +.. autoclass:: MatplotlibDeprecationWarning + +.. 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..9d0161b6aac9 --- /dev/null +++ b/doc/api/next_api_changes/behavior/28437-CH.rst @@ -0,0 +1,11 @@ +*alpha* parameter handling on images +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Prior to Matplotlib 3.10.1, when passing an array to ``imshow(..., alpha=...)``, the +parameter was silently ignored if the image data was an RGB or RGBA image or if +:rc:`image.interpolation_stage` resolved to "rbga". + +Matplotlib 3.10.1 changed this to apply the alpha array as the alpha channel, +overwriting any existing transparency information in the image data. Matplotlib v3.11.0 +further fixes the handling for RGBA images: the existing alpha channel is now multiplied +by the alpha array, consistent with how scalar alpha values are handled. 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/behavior/29958-TH.rst b/doc/api/next_api_changes/behavior/29958-TH.rst new file mode 100644 index 000000000000..cacaf2bac612 --- /dev/null +++ b/doc/api/next_api_changes/behavior/29958-TH.rst @@ -0,0 +1,8 @@ +``Axes.add_collection(..., autolim=True)`` updates view limits +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``Axes.add_collection(..., autolim=True)`` has so far only updated the data limits. +Users needed to additionally call `.Axes.autoscale_view` to update the view limits. +View limits are now updated as well if ``autolim=True``, using a lazy internal +update mechanism, so that the costs only apply once also if you add multiple +collections. diff --git a/doc/api/next_api_changes/behavior/30108-REC.rst b/doc/api/next_api_changes/behavior/30108-REC.rst new file mode 100644 index 000000000000..ce4fb0833207 --- /dev/null +++ b/doc/api/next_api_changes/behavior/30108-REC.rst @@ -0,0 +1,6 @@ +Complex layouts and constrained layout +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Constrained layout now produces smaller spacing between subplots in some +circumstances. This should only affect complex layouts where rows or columns +contain different numbers of subplots, for example a layout created with +``plt.subplot_mosaic('AC;BC', layout='constrained')``. diff --git a/doc/api/next_api_changes/behavior/30272-ES.rst b/doc/api/next_api_changes/behavior/30272-ES.rst new file mode 100644 index 000000000000..5a03f9bc7972 --- /dev/null +++ b/doc/api/next_api_changes/behavior/30272-ES.rst @@ -0,0 +1,2 @@ +``font_manager.findfont`` logs if selected font weight does not match requested +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/api/next_api_changes/behavior/30318-ES.rst b/doc/api/next_api_changes/behavior/30318-ES.rst new file mode 100644 index 000000000000..805901dcb21d --- /dev/null +++ b/doc/api/next_api_changes/behavior/30318-ES.rst @@ -0,0 +1,9 @@ +FT2Font no longer sets a default size +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the interest of handling non-scalable fonts and reducing font initialization, the +`.FT2Font` constructor no longer sets a default size. Non-scalable fonts are sometimes +used for bitmap-backed emoji fonts. + +If metrics are important (i.e., if you are loading character glyphs, or setting a text +string), then explicitly call `.FT2Font.set_size` beforehand. diff --git a/doc/api/next_api_changes/behavior/30335-ES.rst b/doc/api/next_api_changes/behavior/30335-ES.rst new file mode 100644 index 000000000000..26b059401e19 --- /dev/null +++ b/doc/api/next_api_changes/behavior/30335-ES.rst @@ -0,0 +1,15 @@ +``mathtext.VectorParse`` now includes glyph indices +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For a *path*-outputting `.MathTextParser`, in the return value of +`~.MathTextParser.parse`, (a `.VectorParse`), the *glyphs* field is now a list +containing tuples of: + +- font: `.FT2Font` +- fontsize: `float` +- character code: `int` +- glyph index: `int` +- x: `float` +- y: `float` + +Specifically, the glyph index was added after the character code. diff --git a/doc/api/next_api_changes/behavior/30532-TH.rst b/doc/api/next_api_changes/behavior/30532-TH.rst new file mode 100644 index 000000000000..3d368c566039 --- /dev/null +++ b/doc/api/next_api_changes/behavior/30532-TH.rst @@ -0,0 +1,4 @@ +Default name of ``ListedColormap`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default name of `.ListedColormap` has changed from "from_list" to "unnamed". diff --git a/doc/api/next_api_changes/behavior/30634-AL.rst b/doc/api/next_api_changes/behavior/30634-AL.rst new file mode 100644 index 000000000000..585de1ea14eb --- /dev/null +++ b/doc/api/next_api_changes/behavior/30634-AL.rst @@ -0,0 +1,6 @@ +hist2d no longer forces axes limits +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, `.Axes.hist2d` would force the axes x and y limits to the extents +of the histogrammed data, ignoring any other artists. `.Axes.hist2d` now +behaves similarly to `.Axes.imshow`: axes limits are updated to fit the data, +but autoscaling is not otherwise disabled. diff --git a/doc/api/next_api_changes/behavior/30824-AYS.rst b/doc/api/next_api_changes/behavior/30824-AYS.rst new file mode 100644 index 000000000000..a190bd537126 --- /dev/null +++ b/doc/api/next_api_changes/behavior/30824-AYS.rst @@ -0,0 +1,6 @@ +Bivariate colormaps now fully span the intended range of colors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Bivariate colormaps generated by ``SegmentedBivarColormap`` (e.g., ``BiOrangeBlue``) +from a set of input colors now fully span that range of colors. There had been a bug +with the numerical interpolation such that the colormap did not actually include the +first or last colors. diff --git a/doc/api/next_api_changes/behavior/30975-VM.rst b/doc/api/next_api_changes/behavior/30975-VM.rst new file mode 100644 index 000000000000..185b57ac5de6 --- /dev/null +++ b/doc/api/next_api_changes/behavior/30975-VM.rst @@ -0,0 +1,9 @@ +Windows configuration directory location +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On Windows, the default configuration and cache directories now use +``%LOCALAPPDATA%\matplotlib`` instead of ``%USERPROFILE%\.matplotlib``. +This follows Windows application data storage conventions. + +The ``MPLCONFIGDIR`` environment variable can still be used to override +this default. diff --git a/doc/api/next_api_changes/behavior/31021-AYS.rst b/doc/api/next_api_changes/behavior/31021-AYS.rst new file mode 100644 index 000000000000..aa5dc598cb26 --- /dev/null +++ b/doc/api/next_api_changes/behavior/31021-AYS.rst @@ -0,0 +1,7 @@ +Rendering of images now more accurate +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +There have been several fixes to improve the accuracy of how images are +resampled and placed during rendering. Some inaccuracies were up to a pixel off +in the output. The most apparent improvement is that the alignment of data +pixels with tick marks and grid lines is now reliable. Nearly all image output +has changed, but often only at a subtle level that is not obvious qualitatively. diff --git a/doc/api/next_api_changes/behavior/31148-ES.rst b/doc/api/next_api_changes/behavior/31148-ES.rst new file mode 100644 index 000000000000..08ad9b7cb0c1 --- /dev/null +++ b/doc/api/next_api_changes/behavior/31148-ES.rst @@ -0,0 +1,6 @@ +Default *style* parameter of ``image_comparison`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *style* parameter of the `.image_comparison` decorator will become 'mpl20' in +Matplotlib 3.13. Not passing it and relying on the previous default will warn until the +change occurs. diff --git a/doc/api/next_api_changes/behavior/31223-AS.rst b/doc/api/next_api_changes/behavior/31223-AS.rst new file mode 100644 index 000000000000..0880659e55ee --- /dev/null +++ b/doc/api/next_api_changes/behavior/31223-AS.rst @@ -0,0 +1,28 @@ +``pyplot.subplot`` and ``pyplot.subplot_mosaic`` raise *ValueError* on existing figures +---------------------------------------------------------------------------------------- + +Passing a *num* argument to `~.pyplot.subplots` or `~.pyplot.subplot_mosaic` +that refers to an existing figure or is a ``Figure`` instance now raises a +`ValueError`. + +These utility functions are intended strictly for the creation of new figures and +subplots. Previously, they accidentally allowed the reuse of existing figures because +they internally called `~.pyplot.figure`. This change ensures that these functions +strictly follow their documented purpose of creating new figures. + +To reuse an existing figure, clear it first using ``clear=True``: + +.. code-block:: python + + fig, axs = plt.subplots(num=1, clear=True) + # or + fig, axd = plt.subplot_mosaic([['A', 'B']], num=1, clear=True) + +If you have a ``Figure`` instance and want to add subplots to it, use the +object-oriented API: + +.. code-block:: python + + fig.subplots(nrows=2, ncols=2) + # or + fig.subplot_mosaic([['A', 'B']]) diff --git a/doc/api/next_api_changes/behavior/31486-ES.rst b/doc/api/next_api_changes/behavior/31486-ES.rst new file mode 100644 index 000000000000..a04c1d025d90 --- /dev/null +++ b/doc/api/next_api_changes/behavior/31486-ES.rst @@ -0,0 +1,6 @@ +New environment variable to ignore system fonts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +System fonts may be ignored by setting the :envvar:`MPL_IGNORE_SYSTEM_FONTS`; this +suppresses searching for system fonts (in known directories or via some +platform-specific subprocess) as well as limiting the results from `.FontManager.findfont`. diff --git a/doc/api/next_api_changes/behavior/31530-TZ.rst b/doc/api/next_api_changes/behavior/31530-TZ.rst new file mode 100644 index 000000000000..470104817a59 --- /dev/null +++ b/doc/api/next_api_changes/behavior/31530-TZ.rst @@ -0,0 +1,6 @@ +``relim()`` now accounts for Collection artists +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, `~.axes.Axes.relim` did not recalculate data limits for +`.Collection` artists (e.g. those created by `~.axes.Axes.scatter`). +Calling ``ax.relim()`` followed by ``ax.autoscale_view()`` now correctly +includes scatter plots and other collections in the axes limits. diff --git a/doc/api/next_api_changes/behavior/31578-TH.rst b/doc/api/next_api_changes/behavior/31578-TH.rst new file mode 100644 index 000000000000..0607652c7c8f --- /dev/null +++ b/doc/api/next_api_changes/behavior/31578-TH.rst @@ -0,0 +1,10 @@ +SVG links open in new tab or window +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`.Artist.set_url` allows to turn the Artist into a link. In SVG output, +this has been implemented without specifying a `target`_ attribute. The default +target value "_self" resulted in replacing the SVG document with the linked page +when the link was clicked. + +The target is now set to "_blank" so that the link opens in a new tab or window. + +.. _target: https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/target 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/29152_REC.rst b/doc/api/next_api_changes/deprecations/29152_REC.rst new file mode 100644 index 000000000000..cedc91e81410 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/29152_REC.rst @@ -0,0 +1,13 @@ +``pie`` *labels* and *labeldistance* parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Currently the *labels* parameter of `~.Axes.pie` is used both for annotating the +pie wedges directly, and for automatic legend entries. For consistency +with other plotting methods, in future *labels* will only be used for the legend. + +The *labeldistance* parameter will therefore default to ``None`` from Matplotlib +3.14, when it will also be deprecated and then removed in Matplotlib 3.16. To +preserve the existing behavior for now, set ``labeldistance=1.1``. For the longer +term, to place labels on the wedges use the new *wedge_labels* and +*wedge_label_distance* parameters of `~.Axes.pie` or the `~.Axes.pie_label` method. +Note that `~.Axes.pie_label` allows for more customization of the label positions via +the *rotate* and *alignment* parameters as well as *distance*. diff --git a/doc/api/next_api_changes/deprecations/29358-TH.rst b/doc/api/next_api_changes/deprecations/29358-TH.rst new file mode 100644 index 000000000000..1b7a50456afc --- /dev/null +++ b/doc/api/next_api_changes/deprecations/29358-TH.rst @@ -0,0 +1,17 @@ +3rd party scales do not need to have an *axis* parameter anymore +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since matplotlib 3.1 `PR 12831 `_ +scale objects should be reusable and therefore independent of any particular Axis. +Therefore, the use of the *axis* parameter in the ``__init__`` had been discouraged. +However, having that parameter in the signature was still necessary for API +backwards-compatibility. This is no longer the case. + +`.register_scale` now accepts scale classes with or without this parameter. + +The *axis* parameter is pending-deprecated. It will be deprecated in matplotlib 3.13, +and removed in matplotlib 3.15. + +3rd-party scales are recommended to remove the *axis* parameter now if they can +afford to restrict compatibility to matplotlib >= 3.11 already. Otherwise, they may +keep the *axis* parameter and remove it in time for matplotlib 3.13. 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/29993-AL.rst b/doc/api/next_api_changes/deprecations/29993-AL.rst new file mode 100644 index 000000000000..9104fd669325 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/29993-AL.rst @@ -0,0 +1,4 @@ +``testing.widgets.mock_event`` and ``testing.widgets.do_event`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... are deprecated. Directly construct Event objects (typically `.MouseEvent` +or `.KeyEvent`) and pass them to ``canvas.callbacks.process()`` instead. 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/deprecations/30163-AL.rst b/doc/api/next_api_changes/deprecations/30163-AL.rst new file mode 100644 index 000000000000..15d0077375f2 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30163-AL.rst @@ -0,0 +1,9 @@ +``matplotlib.style.core`` +~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``matplotlib.style.core`` module is deprecated. All APIs intended for +public use are now available in `matplotlib.style` directly (including +``USER_LIBRARY_PATHS``, which was previously not reexported). + +The following APIs of ``matplotlib.style.core`` have been deprecated with no +replacement: ``BASE_LIBRARY_PATH``, ``STYLE_EXTENSION``, ``STYLE_BLACKLIST``, +``update_user_library``, ``read_style_directory``, ``update_nested_dict``. diff --git a/doc/api/next_api_changes/deprecations/30322-ES.rst b/doc/api/next_api_changes/deprecations/30322-ES.rst new file mode 100644 index 000000000000..b9c4964e58c8 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30322-ES.rst @@ -0,0 +1,7 @@ +Font kerning factor is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Due to internal changes to support complex text rendering, the kerning factor on fonts is +no longer used. Setting the ``text.kerning_factor`` rcParam (which existed only for +backwards-compatibility) to any value other than None is deprecated, and the rcParam will +be removed in the future. diff --git a/doc/api/next_api_changes/deprecations/30329-ES.rst b/doc/api/next_api_changes/deprecations/30329-ES.rst new file mode 100644 index 000000000000..8d5060c4821b --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30329-ES.rst @@ -0,0 +1,4 @@ +``font_manager.is_opentype_cff_font`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There is no replacement. diff --git a/doc/api/next_api_changes/deprecations/30349-AL.rst b/doc/api/next_api_changes/deprecations/30349-AL.rst new file mode 100644 index 000000000000..78e26f41889f --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30349-AL.rst @@ -0,0 +1,3 @@ +``Axes.set_navigate_mode`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... with no replacement. diff --git a/doc/api/next_api_changes/deprecations/30364-AS.rst b/doc/api/next_api_changes/deprecations/30364-AS.rst new file mode 100644 index 000000000000..4f5493b8b706 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30364-AS.rst @@ -0,0 +1,4 @@ +Parameters ``Axes3D.set_aspect(..., anchor=..., share=...)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The parameters *anchor* and *share* of `.Axes3D.set_aspect` are deprecated. +They had no effect on 3D axes and will be removed in a future version. diff --git a/doc/api/next_api_changes/deprecations/30368-AL.rst b/doc/api/next_api_changes/deprecations/30368-AL.rst new file mode 100644 index 000000000000..efd3c8360ef3 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30368-AL.rst @@ -0,0 +1,3 @@ +``GridFinder.get_grid_info`` now takes a single bbox as parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Passing ``x1, y1, x2, y2`` as separate parameters is deprecated. diff --git a/doc/api/next_api_changes/deprecations/30369-AL.rst b/doc/api/next_api_changes/deprecations/30369-AL.rst new file mode 100644 index 000000000000..8b82c80054d9 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30369-AL.rst @@ -0,0 +1,14 @@ +:mod:`.axisartist` now uses more standard tick direction controls +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, the position of :mod:`.axisartist` ticks (inside or outside +the axes) were set using ``set_tick_out(bool)``. They are now set +using ``set_tick_direction("in")`` (or "out", or "inout"), and respect +:rc:`xtick.direction` and :rc:`ytick.direction`. In particular, they default +to pointing outwards, consistently with the rest of the library. + +The *tick_out* parameter of `.Ticks` has been deprecated (use *tick_direction* +instead). The ``Ticks.get_tick_out`` method is deprecated (use +`.Ticks.get_tick_direction` instead). + +The unused ``locs_angles_labels`` attribute of `.Ticks` and `.LabelBase` has +also been deprecated. diff --git a/doc/api/next_api_changes/deprecations/30469-AL.rst b/doc/api/next_api_changes/deprecations/30469-AL.rst new file mode 100644 index 000000000000..ef3f042843c2 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30469-AL.rst @@ -0,0 +1,4 @@ +The *axes* parameter of ``RadialLocator`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated. `~.polar.RadialLocator` now fetches the relevant information +from the Axis' parent Axes. diff --git a/doc/api/next_api_changes/deprecations/30512-ES.rst b/doc/api/next_api_changes/deprecations/30512-ES.rst new file mode 100644 index 000000000000..f235964c5502 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30512-ES.rst @@ -0,0 +1,3 @@ +``PdfFile.multi_byte_charprocs`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated with no replacement. diff --git a/doc/api/next_api_changes/deprecations/30531-TH.rst b/doc/api/next_api_changes/deprecations/30531-TH.rst new file mode 100644 index 000000000000..19d51fd2fb6c --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30531-TH.rst @@ -0,0 +1,16 @@ +In-place modifications of colormaps +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Colormaps are planned to become immutable in the long term. + +As a first step, in-place modifications of colormaps are now pending-deprecated. +This affects the following methods of `.Colormap`: + +- `.Colormap.set_bad` - use ``cmap.with_extremes(bad=...)`` instead +- `.Colormap.set_under` - use ``cmap.with_extremes(under=...)`` instead +- `.Colormap.set_over` - use ``cmap.with_extremes(over=...)`` instead +- `.Colormap.set_extremes` - use ``cmap.with_extremes(...)`` instead + +Use the respective `.Colormap.with_extremes` and appropriate keyword arguments +instead which returns a copy of the colormap (available since matplotlib 3.4). +Alternatively, if you create the colormap yourself, you can also pass the +respective arguments to the constructor (available since matplotlib 3.11). diff --git a/doc/api/next_api_changes/deprecations/30737-TH.rst b/doc/api/next_api_changes/deprecations/30737-TH.rst new file mode 100644 index 000000000000..8feef85912b4 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30737-TH.rst @@ -0,0 +1,8 @@ +The *canvas* parameter to ``MultiCursor`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated. It has been unused for a while already. + +Please remove the parameter and change the call from +``MultiCursor(canvas, axes)`` to ``MultiCursor(axes)``. Both calls are +valid throughout the deprecation period. diff --git a/doc/api/next_api_changes/deprecations/30844-IHI.rst b/doc/api/next_api_changes/deprecations/30844-IHI.rst new file mode 100644 index 000000000000..55ebe9af6d68 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30844-IHI.rst @@ -0,0 +1,6 @@ +``CallbackRegistry.disconnect`` *cid* parameter renamed to *cid_or_func* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The *cid* parameter of `.CallbackRegistry.disconnect` has been renamed to +*cid_or_func*. The method now also accepts a callable, which will disconnect +that callback from all signals or from a specific signal if the *signal* +keyword argument is provided. diff --git a/doc/api/next_api_changes/deprecations/30889-TH.rst b/doc/api/next_api_changes/deprecations/30889-TH.rst new file mode 100644 index 000000000000..d221ae30d4fb --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30889-TH.rst @@ -0,0 +1,10 @@ +Transforms helper functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following functions in the `.transforms` module are deprecated, +because they are considerer internal functionality and should not be used +by end users: + +- ``matplotlib.transforms.nonsingular`` +- ``matplotlib.transforms.interval_contains`` +- ``matplotlib.transforms.interval_contains_open`` diff --git a/doc/api/next_api_changes/deprecations/30993-SS.rst b/doc/api/next_api_changes/deprecations/30993-SS.rst new file mode 100644 index 000000000000..152d25ba438d --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30993-SS.rst @@ -0,0 +1,5 @@ +``InvertedSymmetricalLogTransform.invlinthresh`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``invlinthresh`` attribute of `.InvertedSymmetricalLogTransform` is +deprecated. Use the ``.inverted().transform(linthresh)`` method instead. diff --git a/doc/api/next_api_changes/deprecations/31023-AL.rst b/doc/api/next_api_changes/deprecations/31023-AL.rst new file mode 100644 index 000000000000..ac2e8be2e708 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/31023-AL.rst @@ -0,0 +1,4 @@ +``cbook.normalize_kwargs`` only supports passing artists and artist classes as second argument +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Support for directly passing an alias mapping or None as second argument to +`.cbook.normalize_kwargs` has been deprecated. diff --git a/doc/api/next_api_changes/deprecations/31143-AL.rst b/doc/api/next_api_changes/deprecations/31143-AL.rst new file mode 100644 index 000000000000..7de02ff83896 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/31143-AL.rst @@ -0,0 +1,3 @@ +``backend_svg.XMLWriter`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It is an internal helper not intended for external use. diff --git a/doc/api/next_api_changes/deprecations/31170-AL.rst b/doc/api/next_api_changes/deprecations/31170-AL.rst new file mode 100644 index 000000000000..ecf1f31f1cff --- /dev/null +++ b/doc/api/next_api_changes/deprecations/31170-AL.rst @@ -0,0 +1,6 @@ +``kw``, ``fontproperties``, ``labelcolor``, and ``verts`` attributes of ``QuiverKey`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These attributes are deprecated (note that ``fontproperties``, ``labelcolor``, +or ``verts`` after the first draw had no effect previously). Directly +access the relevant attributes on the sub-artists ``QuiverKey.vector`` and +``QuiverKey.text``, instead. diff --git a/doc/api/next_api_changes/deprecations/31248-SS.rst b/doc/api/next_api_changes/deprecations/31248-SS.rst new file mode 100644 index 000000000000..1d7adbdf0fde --- /dev/null +++ b/doc/api/next_api_changes/deprecations/31248-SS.rst @@ -0,0 +1,9 @@ +Arbitrary code in ``axes.prop_cycle`` rcParam strings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``axes.prop_cycle`` rcParam accepts Python expressions that are evaluated +in a limited context. The evaluation context has been further limited and some +expressions that previously worked (list comprehensions, for example) no longer +will. This change is made without a deprecation period to improve security. +The previously documented cycler operations at +https://matplotlib.org/cycler/ are still supported. diff --git a/doc/api/next_api_changes/deprecations/31347-TH.rst b/doc/api/next_api_changes/deprecations/31347-TH.rst new file mode 100644 index 000000000000..991406e08b97 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/31347-TH.rst @@ -0,0 +1,8 @@ +Contour labelling on filled contours +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using `~.Axes.clabel` to label filled contours created with `~.Axes.contourf` is deprecated. ``clabel()`` +is designed to label contour lines (`.Axes.contour`), and using it with filled contours can lead to inconsistent +plots. If you want to add labels to filled contours, the recommended approach is to first create the filled contours +with `~.Axes.contourf`, then overlay contour lines using `~.Axes.contour`, and finally apply `~.Axes.clabel` to those +contour lines for labeling. For an example see :doc:`/gallery/images_contours_and_fields/contourf_demo`. diff --git a/doc/api/next_api_changes/deprecations/31416-TH.rst b/doc/api/next_api_changes/deprecations/31416-TH.rst new file mode 100644 index 000000000000..6d6d4b7b7809 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/31416-TH.rst @@ -0,0 +1,8 @@ +Formatter attributes +~~~~~~~~~~~~~~~~~~~~ + +These following attributes are considered internal and users should not have a need to access them: + +- `.ScalarFormatter`: ``orderOfMagnitude`` and ``format`` +- `.ConciseDateFormatter`: ``offset_format`` +- `.Formatter`: ``locs`` diff --git a/doc/api/next_api_changes/deprecations/31468-ES.rst b/doc/api/next_api_changes/deprecations/31468-ES.rst new file mode 100644 index 000000000000..a71644a6e4f5 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/31468-ES.rst @@ -0,0 +1,6 @@ +``image.thumbnail`` +~~~~~~~~~~~~~~~~~~~ + +... is deprecated without replacement. Use :external:py:`Pillow's thumbnail +method ` instead. See also the `Pillow tutorial +`_. diff --git a/doc/api/next_api_changes/deprecations/31521-ES.rst b/doc/api/next_api_changes/deprecations/31521-ES.rst new file mode 100644 index 000000000000..fc04b69a50fd --- /dev/null +++ b/doc/api/next_api_changes/deprecations/31521-ES.rst @@ -0,0 +1,7 @@ +Font hinting factor is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Due to internal changes to support complex text rendering, the hinting factor on fonts is +no longer used. Setting the ``text.hinting_factor`` rcParam to any value other than None +is deprecated, and the rcParam will be removed in the future. Likewise, passing the +``hinting_factor`` argument to the `.FT2Font` constructor is deprecated. diff --git a/doc/api/next_api_changes/deprecations/31630-ES.rst b/doc/api/next_api_changes/deprecations/31630-ES.rst new file mode 100644 index 000000000000..2509b4323022 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/31630-ES.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 is deprecated for 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/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/29181-ES.rst b/doc/api/next_api_changes/development/29181-ES.rst new file mode 100644 index 000000000000..a3c7e5eed448 --- /dev/null +++ b/doc/api/next_api_changes/development/29181-ES.rst @@ -0,0 +1,11 @@ +pip 25.1 suggested for development +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dependencies for development (build and testing) are now specified as `Dependency Groups +`_ +instead of `individual requirements files +`_. + +Consequently, a version of pip that supports Dependency Groups is suggested, namely +version 25.1 or higher. Note that if you install build/testing dependencies manually (by +copying the list from ``pyproject.toml``), then an older version of pip is sufficient. 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/development/30143-ES.rst b/doc/api/next_api_changes/development/30143-ES.rst new file mode 100644 index 000000000000..2d79ad6bbe9d --- /dev/null +++ b/doc/api/next_api_changes/development/30143-ES.rst @@ -0,0 +1,7 @@ +Glyph indices now typed distinctly from character codes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, character codes and glyph indices were both typed as `int`, which means you +could mix and match them erroneously. While the character code can't be made a distinct +type (because it's used for `chr`/`ord`), typing glyph indices as a distinct type means +these can't be fully swapped. 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/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/next_api_changes/removals/31588-ES.rst b/doc/api/next_api_changes/removals/31588-ES.rst new file mode 100644 index 000000000000..8709c5a77f5f --- /dev/null +++ b/doc/api/next_api_changes/removals/31588-ES.rst @@ -0,0 +1,18 @@ +``boxplot`` tick labels +^^^^^^^^^^^^^^^^^^^^^^^ + +The parameter *labels* has been removed in favour of *tick_labels* for clarity and +consistency with `~.Axes.bar`. + +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 +has been removed; 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/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..8caef5e35ced --- /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 in the 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..513971098b93 --- /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. Implementers 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..71a2f71efc94 --- /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 an RGB or RBGA image or if :rc:`image.interpolation_stage` +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.10.7.rst b/doc/api/prev_api_changes/api_changes_3.10.7.rst new file mode 100644 index 000000000000..a60061e86277 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.10.7.rst @@ -0,0 +1,10 @@ +API Changes for 3.10.7 +====================== + +Development +----------- + +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/prev_api_changes/api_changes_3.10.9.rst b/doc/api/prev_api_changes/api_changes_3.10.9.rst new file mode 100644 index 000000000000..592faadc347b --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.10.9.rst @@ -0,0 +1,20 @@ +API Changes for 3.10.9 +====================== + + +Deprecations +------------ + + +Arbitrary code in ``axes.prop_cycle`` rcParam strings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``axes.prop_cycle`` rcParam accepts Python expressions that are evaluated +in a limited context. The evaluation context has been further limited and some +expressions that previously worked (list comprehensions, for example) no longer +will. This change is made without a deprecation period to improve security. +The previously documented cycler operations at +https://matplotlib.org/cycler/ are still supported. + +This change was originally slated for v3.11.0 of Matplotlib, but was additionally +backported due to the security implications. 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..04836687f76a --- /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 + ``ConnectionPatch.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..56b3ad5c253e --- /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 + ``ConnectionPatch.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..97d9c576cc86 100644 --- a/doc/api/pyplot_summary.rst +++ b/doc/api/pyplot_summary.rst @@ -1,8 +1,340 @@ -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 + pie_label + 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 index 10576f4559d6..0900bf46cc75 100644 --- a/doc/api/style_api.rst +++ b/doc/api/style_api.rst @@ -1,10 +1,15 @@ -***** -style -***** +******************** +``matplotlib.style`` +******************** +Styles are predefined sets of `.rcParams` that define the visual appearance of +a plot. -:mod:`matplotlib.style` -======================= +: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: @@ -12,10 +17,17 @@ style :show-inheritance: :imported-members: -.. data:: matplotlib.style.library +.. 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. - Dictionary of available styles +.. data:: available -.. data:: matplotlib.style.available + List of the names of the available styles. - List of 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..ba8f4886b19f 100644 --- a/doc/api/ticker_api.rst +++ b/doc/api/ticker_api.rst @@ -1,12 +1,13 @@ -****** -ticker -****** - - -:mod:`matplotlib.ticker` -========================== +********************* +``matplotlib.ticker`` +********************* .. automodule:: matplotlib.ticker :members: :undoc-members: + :special-members: __call__ :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..20fe81e574fe --- /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. + +.. _Mayavi: https://docs.enthought.com/mayavi/mayavi/ diff --git a/doc/api/toolkits/mplot3d/view_angles.rst b/doc/api/toolkits/mplot3d/view_angles.rst new file mode 100644 index 000000000000..e4200cd2d0e4 --- /dev/null +++ b/doc/api/toolkits/mplot3d/view_angles.rst @@ -0,0 +1,204 @@ +.. _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-block:: python + + 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. + +.. _MATLAB: https://www.mathworks.com/help/matlab/ref/view.html + +.. [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..b63222eda43d --- /dev/null +++ b/doc/api/typing_api.rst @@ -0,0 +1,63 @@ +********************* +``matplotlib.typing`` +********************* + +.. automodule:: matplotlib.typing + :no-members: + :no-undoc-members: + +.. types are written out explicitly as `.. autodata::` directives, so that we + can meaningfully group them in sections. + test_typing.py::test_typing_aliases_documented ensures that the documented + types are in sync with the actual types defined in matplotlib.typing. + +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 + +Artist styles +============= + +.. autodata:: matplotlib.typing.LineStyleType +.. autodata:: matplotlib.typing.DrawStyleType +.. autodata:: matplotlib.typing.MarkEveryType +.. autodata:: matplotlib.typing.MarkerType +.. autodata:: matplotlib.typing.FillStyleType +.. autodata:: matplotlib.typing.CapStyleType +.. autodata:: matplotlib.typing.JoinStyleType + +Events +====== + +.. autodata:: matplotlib.typing.MouseEventType +.. autodata:: matplotlib.typing.KeyEventType +.. autodata:: matplotlib.typing.DrawEventType +.. autodata:: matplotlib.typing.PickEventType +.. autodata:: matplotlib.typing.ResizeEventType +.. autodata:: matplotlib.typing.CloseEventType +.. autodata:: matplotlib.typing.EventType + +rcParams and stylesheets +======================== + +.. autodata:: matplotlib.typing.RcKeyType +.. autodata:: matplotlib.typing.RcGroupKeyType +.. autodata:: matplotlib.typing.RcStyleType + +Other types +=========== + +.. autodata:: matplotlib.typing.CoordsType +.. autodata:: matplotlib.typing.LegendLocType +.. autodata:: matplotlib.typing.LogLevel +.. autodata:: matplotlib.typing.HashableList + + +.. intentionally undocumented types (one type per row) + CoordsBaseType 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..30b6c6758d6b 100644 --- a/doc/api/widgets_api.rst +++ b/doc/api/widgets_api.rst @@ -1,12 +1,55 @@ -******* -widgets -******* +********************** +``matplotlib.widgets`` +********************** - -:mod:`matplotlib.widgets` -========================= +.. currentmodule:: matplotlib.widgets .. automodule:: matplotlib.widgets - :members: - :undoc-members: - :show-inheritance: + :no-members: + :no-undoc-members: + + +Widget classes +============== + +.. inheritance-diagram:: matplotlib.widgets.Widget + :parts: 1 + :private-bases: + :include-subclasses: + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Widget + AxesWidget + Cursor + MultiCursor + Button + _Buttons + CheckButtons + RadioButtons + SliderBase + Slider + RangeSlider + TextBox + _SelectorWidget + RectangleSelector + EllipseSelector + Lasso + LassoSelector + PolygonSelector + SpanSelector + SubplotTool + +Helper classes +============== + +.. autosummary:: + :toctree: _as_gen + :nosignatures: + + LockDraw + ToolHandles + ToolLineHandles diff --git a/doc/conf.py b/doc/conf.py index 571def2e02c1..6651383fcacb 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,60 +1,361 @@ -# -*- 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 = [ + 'release/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.rcparams', + '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' + patch_header = 'sphinxext.util.patch_header' + matplotlib_reduced_latex_scraper = 'sphinxext.util.matplotlib_reduced_latex_scraper' +else: + # 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, + patch_header) + +if parse_version(sphinx_gallery.__version__) >= parse_version('0.17.0'): + sg_matplotlib_animations = (True, 'mp4') else: - print("Using IPython's ipython_console_highlighting directive") - extensions.append('IPython.sphinxext.ipython_console_highlighting') + sg_matplotlib_animations = True -try: - import numpydoc -except ImportError: - raise ImportError("No module named numpydoc - you need to install " - "numpydoc to build the documentation.") + +# 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') +# 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/docs/', 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), + 'wx': ('https://docs.wxpython.org/', 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'), + 'minigallery_sort_order': 'sphinxext.gallery_order.preserve_order', + # 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, patch_header), + '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'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -65,22 +366,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 +402,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 +410,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,52 +428,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'), - ('scales', 'Axis scales'), - ('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, @@ -170,45 +549,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. + "release/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 # ------------------------ @@ -216,16 +612,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'), ] @@ -233,27 +628,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 = [] @@ -261,71 +738,116 @@ # 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 - +# numpydoc config -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 - - 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') + + +# ----------------------------------------------------------------------------- +# 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) + app.config.autodoc_use_legacy_class_based = True 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..2b39959eaca7 --- /dev/null +++ b/doc/devel/MEP/MEP10.rst @@ -0,0 +1,189 @@ +============================== + 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..03bc3013b3e3 --- /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.pypa.io/en/latest/deprecated/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..d79d3c2d3115 --- /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://github.com/GNOME/pango +.. _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..6880cf10ae62 --- /dev/null +++ b/doc/devel/api_changes.rst @@ -0,0 +1,347 @@ +.. _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 new rcParams +^^^^^^^^^^^^^^^^ + +When adding a new rcParam, the following files must be updated: + +1. :file:`lib/matplotlib/rcsetup.py` - Add a validator entry to the + ``_validators`` dict and a corresponding ``_Param`` entry with default value + and description. +2. :file:`lib/matplotlib/mpl-data/matplotlibrc` - Add a commented-out entry + showing the default value. +3. :file:`lib/matplotlib/typing.py` - Add the key to the ``RcKeyType`` Literal + so that it is recognized as a valid rcParam key. + + +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/release/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:: ../release/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 2ed7a0309720..7a4b296b52ce 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,113 +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: + +Use 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! - # 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... -Hints -===== +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. -This section describes how to add certain kinds of new features to -matplotlib. +- `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. -.. _custom_backend: +By default, `logging` displays all log messages at levels higher than +``logging.WARNING`` to `sys.stderr`. -Developing a new backend ------------------------- +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. -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 +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:: -* in matplotlibrc:: + # in my_matplotlib_module.py + import warnings - backend : module://my_backend + def set_range(bottom, top): + if bottom == top: + warnings.warn('Attempting to set identical bottom==top') +running the script:: -* with the :envvar:`MPLBACKEND` environment variable:: + from matplotlib import my_matplotlib_module + my_matplotlib_module.set_range(0, 0) # set range - > export MPLBACKEND="module://my_backend" - > python simple_plot.py +will display -* from the command shell with the `-d` flag:: +.. code-block:: none - > python simple_plot.py -dmodule://my_backend + UserWarning: Attempting to set identical bottom==top + warnings.warn('Attempting to set identical bottom==top') -* with the use directive in your script:: +Modifying the module to use `._api.warn_external`:: - import matplotlib - matplotlib.use('module://my_backend') + 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..a0056b80e606 --- /dev/null +++ b/doc/devel/communication_guide.rst @@ -0,0 +1,315 @@ +.. _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. + + +Moderation +========== +Moderation rights are granted specific to each :ref:`official platform `. +All matplotlib maintainers are moderators on github. If you are interested in moderating +any of the other platforms: + +* 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. + * Explain why you want moderation rights + +Enforcement responsibilities +---------------------------- +Any person with moderation rights is granted the authority to clarify and +enforce our standards of expected behavior. This is a supplement to our Code of Conduct, +not a replacement; moderators should make use of the :ref:`code_of_conduct` process for +CoC violations. In addition violations of platform specific terms of service should be +reported to that platform. + +Moderators may hide, edit, or reject comments, commits, code, wiki edits, issues, and +other contributions that do not comply with our :ref:`contributing guidelines `. +Deletion should only be used to remove sensitive information that can not be removed +through edits. On most platforms, these actions can be accessed through the [...] context +menu. + +Communication +^^^^^^^^^^^^^ +After taking action, Moderators should publicly communicate their reasons for +doing so to the user when possible, e.g. when doing so will not reveal sensitive +information. When the situation is sensitive, moderators should reassess whether the +situation would be better handled through the code of conduct process and attempt to +communicate privately with the user (e.g. DMs) if appropriate. + +Consequences +^^^^^^^^^^^^ +Moderators have the right and responsibility to enforce consequences for disruptive +behavior. Moderators are welcome to consult on levying consequences in the ``staff`` +discourse channel. When possible, this should be done in the following stages: + +* warn: alert the user of their misconduct and how they can remedy the situation + - this can be done privately and then publicly if the behavior persists + - second warning should mention consequence of not heeding warning +* temporary ban: apply a short term ban from the platform (default 1 week) + - temporary bans can be applied in increasing increments at the moderator's discretion +* permanent ban from the platform + +If the user has not modified their behavior in an acceptable fashion, then the moderator +can move to the next stage. Moderators should notify the other maintainers of temporary +and permanent bans via the ``staff`` discourse channel or at the weekly developer meeting. +When feasible, moderators should also maintain a record of the unacceptable behavior. If +the user would like to appeal a ban (on any platform), moderators should make use of the +code of conduct process to resolve the situation by directing the user to file a code of +conduct report. + +Moderators may immediately ban users in extenuating circumstance, such as while a +CoC or TOS report is being investigated or when the user is an agent or bot. Moderators +should file a code of conduct report for (human) users they feel should be permanently +banned from all platforms. + + +.. _communication-channels: + +Official project platforms +========================== +The Scientific Python community uses various 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://discourse.matplotlib.org/chat/c/community/3 `_ +* 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 on Discourse: `Community `_ + +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 confuzzlement. + + +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. github, discourse, 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..cf158cbe67ad --- /dev/null +++ b/doc/devel/contribute.rst @@ -0,0 +1,399 @@ +.. 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 + + Here are a few typical new contributor profiles. If you + don't fit into one of them, come talk to us on `Discourse + `_ about how you might contribute. + + * **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 + `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 `__ + in our issue tracker, and we'll be happy to discuss technical approaches. + + If you can implement the solution yourself, even better! Consider contributing + the change as a :ref:`pull request ` right away. + + * **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. Start by building your experience in + using Matplotlib: make complicated visualizations, use niche features, + dive deep into one part of the library. This will help you build the + context to then look at the existing issues and pull requests. You can + then reach out to us at the :ref:`new contributor ` + meeting or Discourse channel (incubator) to discuss what you would like + to work on. + +.. _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: + +Use of Generative AI +==================== + +Generative AI tools are evolving rapidly and can be helpful. As with any tool, +the resulting contribution is the responsibility of the contributor. We +expect dedicated and authentic engagement in our community. In particular when +using AI, carefully consider what and how to communicate, question results, +think things through thoroughly and make well-informed decisions. + +Some examples of acceptable and unacceptable AI uses are: + +.. grid:: 1 1 2 2 + + .. grid-item:: + + :octicon:`check;1em;sd-text-success` **Acceptable uses** + + - Gaining understanding of the existing code + - Getting solution ideas + - Translating or proof-reading your comments or PR descriptions. Please keep + the wording as close as possible to your original wording. + + .. grid-item:: + + :octicon:`x;1em;sd-text-danger` **Unacceptable uses** + + - External AI tooling (e.g. bots, agents) directly interacting with the project; + including creating issues, PRs or commenting on GitHub or Discourse. + - Solving topics that you wouldn't be able to solve yourself without AI + - Using AI output without ensuring that you fully understand the output or + without verifying that it is the correct approach. + +To ensure project health and preserve limited core developer capacity, we will flag +and reject low-value contributions that we believe are AI generated. We may ban +and/or report users to GitHub if they harm the project or its community through +irresponsible use of AI. + +.. _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 `incubator chat`_ 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 public chat room on Discourse_ 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, go to Discourse_ and click on the chat bubble icon next to the search +icon at the top right of the page. Then, find the "Incubator" channel. + +.. _Discourse: https://discourse.matplotlib.org/ +.. _development chat: https://discourse.matplotlib.org/chat/c/matplotlib/2 +.. _community chat: https://discourse.matplotlib.org/chat/c/community/3 +.. _incubator chat: https://discourse.matplotlib.org/chat/c/incubator/4 + +.. _good_first_issues: + +Good first issues +----------------- + +We have marked some issues as `good first issue +`_ because we +think they are a good entry point into the process of contributing to Matplotlib. These +issues are well documented, do not require a deep understanding of the internals of +Matplotlib, and do not need urgent resolution. Good first issues are intended to onboard +newcomers with a genuine interest in improving Matplotlib, in the hopes that they will +continue to participate in our development community; therefore, pull requests that are +:ref:`AI generated ` will be closed. + +.. _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 a reasonable time frame?" This should (at most) + be a few days for an easy issue. If it takes longer, let us know why. + * If you are new to open source, we strongly recommend that you do not choose a + complicated issue for your first contribution - please ask in the incubator + channel if you need help gauging the complexity of the work. +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 there is no pull request, :ref:`create a new pull request `. +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 `_. + +.. important:: + + Make sure you finish addressing any review comments on your first PR and wait + for it to be merged (or closed) before opening a new one. It can be a valuable + learning experience to go through the review process and to get feedback on + your contribution, while also helping maintainers spend their time + effectively. + +.. 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`, +including the chat space on Discourse_. For development questions we recommend +reaching out on our `development chat`_ and for community questions reach out at +the `community chat`_. + +.. _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. + +Difficulty +---------- +Issues may additionally be tagged with a difficulty. ``Difficulty: Easy`` is suitable +for people with beginner scientific Python experience, i.e. fluency with Python syntax +and some experience using libraries like Numpy, Pandas, or Xarray. ``Difficulty: Medium`` +and ``Difficulty: Hard`` require more programming experience. This could be for a variety +of reasons, for example: + +- requires understanding intermediate to advanced Python features, such as decorators, + context managers, or meta-programming +- is in areas of the code base which have more interdependencies or is legacy code. +- involves complex or significant changes to algorithms or architecture. + +Generally, the difficulty level is correlated with how much conceptual (and contextual) +understanding of Matplotlib is required to resolve it. + +.. _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 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..2ee9193c9fa5 --- /dev/null +++ b/doc/devel/development_setup.rst @@ -0,0 +1,357 @@ +.. 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: + +================= +Development setup +================= + +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 `_ + * :external+scipy:ref:`using-git` + * :external+scipy: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 -U pip # You may skip this step if pip 25.1 is already available. + pip install --group dev + + 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 --group dev --editable . + +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 `discourse `_ +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 +======================== +`prek `_ 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 prek + prek 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 :: + + prek run --all-files + +To run a particular hook manually, run ``prek run`` with the hook id :: + + prek 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..99c7e29234aa --- /dev/null +++ b/doc/devel/development_workflow.rst @@ -0,0 +1,594 @@ +.. 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 `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-new-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-new-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, make a +:ref:`draft pull request ` and state what aspects you want to have +feedback on. 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 my-new-feature + + 8630830 my-new-feature@{0}: commit: BUG: io: close file handles immediately + 278dd2a my-new-feature@{1}: rebase finished: refs/heads/my-new-feature onto 11ee694744f2552d + 26aa21a my-new-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 my-new-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 + b7e99a8659 (HEAD -> my-new-feature) Fix some remaining bugs + 8a5de78b17 Modify it so that it works + 34448c69eb Fix a few bugs + disable + 9a5d1ca186 First implementation + d1da6fbf0b (upstream/main) Merge pull request #30778 from timhoffm/decorator-tracebackhide + 6ad937ad83 Merge pull request #30838 from has2k1/fix-numpy-integer-markers + ... + +and ``b7e99a8659`` is the most recent commit in the ``my-new-feature`` branch. Suppose we +want to make the following changes: + +* Rewrite the commit message for ``9a5d1ca186`` to something more specific. +* Combine the commits ``34448c69eb``, ``8a5de78b17``, ``b7e99a8659`` into a single one. + +We do as follows:: + + # make a backup of the current state + git branch tmp HEAD + # interactive rebase + git rebase -i d1da6fbf0b + +This will open an editor with the following text in it:: + + pick 9a5d1ca186 First implementation + pick 34448c69eb Fix a few bugs + disable + pick 8a5de78b17 Modify it so that it works + pick b7e99a8659 Fix some remaining bugs + + # Rebase d1da6fbf0b..b7e99a8659 onto d1da6fbf0b (4 commands) + # + # 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 [-C | -c] = like "squash" but keep only the previous + # commit's log message, unless -C is used, in which case + # keep only this commit's message; -c is same as -C but + # opens the editor + # x, exec = run command (the rest of the line) using shell + # b, break = stop here (continue rebase later with 'git rebase --continue') + # d, drop = remove commit + # l, label ` +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/release/prev_whats_new/whats_new_3.4.0.rst b/doc/release/prev_whats_new/whats_new_3.4.0.rst new file mode 100644 index 000000000000..3cddee85b56e --- /dev/null +++ b/doc/release/prev_whats_new/whats_new_3.4.0.rst @@ -0,0 +1,1041 @@ +.. redirect-from:: /users/prev_whats_new/whats_new_3.4.0 + +.. _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/release/prev_whats_new/whats_new_3.5.0.rst b/doc/release/prev_whats_new/whats_new_3.5.0.rst new file mode 100644 index 000000000000..d43a390d2db9 --- /dev/null +++ b/doc/release/prev_whats_new/whats_new_3.5.0.rst @@ -0,0 +1,683 @@ +.. redirect-from:: /users/prev_whats_new/whats_new_3.5.0 + +============================================= +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/release/prev_whats_new/whats_new_3.5.2.rst b/doc/release/prev_whats_new/whats_new_3.5.2.rst new file mode 100644 index 000000000000..98880653c9d8 --- /dev/null +++ b/doc/release/prev_whats_new/whats_new_3.5.2.rst @@ -0,0 +1,22 @@ +.. redirect-from:: /users/prev_whats_new/whats_new_3.5.2 + +============================================= +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/release/prev_whats_new/whats_new_3.6.0.rst b/doc/release/prev_whats_new/whats_new_3.6.0.rst new file mode 100644 index 000000000000..57b162ca159d --- /dev/null +++ b/doc/release/prev_whats_new/whats_new_3.6.0.rst @@ -0,0 +1,890 @@ +.. redirect-from:: /users/prev_whats_new/whats_new_3.6.0 + +============================================= +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/release/prev_whats_new/whats_new_3.7.0.rst b/doc/release/prev_whats_new/whats_new_3.7.0.rst new file mode 100644 index 000000000000..d2451bfa50bc --- /dev/null +++ b/doc/release/prev_whats_new/whats_new_3.7.0.rst @@ -0,0 +1,453 @@ +.. redirect-from:: /users/prev_whats_new/whats_new_3.7.0 + +============================================= +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/release/prev_whats_new/whats_new_3.8.0.rst b/doc/release/prev_whats_new/whats_new_3.8.0.rst new file mode 100644 index 000000000000..2d5ffe3ad3e7 --- /dev/null +++ b/doc/release/prev_whats_new/whats_new_3.8.0.rst @@ -0,0 +1,531 @@ +.. redirect-from:: /users/prev_whats_new/whats_new_3.8.0 + +============================================== +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 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 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/release/prev_whats_new/whats_new_3.9.0.rst b/doc/release/prev_whats_new/whats_new_3.9.0.rst new file mode 100644 index 000000000000..259bd2f35ee4 --- /dev/null +++ b/doc/release/prev_whats_new/whats_new_3.9.0.rst @@ -0,0 +1,411 @@ +.. redirect-from:: /users/prev_whats_new/whats_new_3.9.0 + +============================================= +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/release/release_notes.rst b/doc/release/release_notes.rst new file mode 100644 index 000000000000..d652f5dbcf0f --- /dev/null +++ b/doc/release/release_notes.rst @@ -0,0 +1,291 @@ +.. redirect-from:: /api/api_changes_old +.. redirect-from:: /users/whats_new_old +.. redirect-from:: /users/release_notes + +.. _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.11 +^^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + github_stats.rst + +Version 3.10 +^^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.10.0.rst + ../api/prev_api_changes/api_changes_3.10.9.rst + ../api/prev_api_changes/api_changes_3.10.7.rst + ../api/prev_api_changes/api_changes_3.10.1.rst + ../api/prev_api_changes/api_changes_3.10.0.rst + prev_whats_new/github_stats_3.10.9.rst + prev_whats_new/github_stats_3.10.8.rst + prev_whats_new/github_stats_3.10.7.rst + prev_whats_new/github_stats_3.10.6.rst + prev_whats_new/github_stats_3.10.5.rst + prev_whats_new/github_stats_3.10.3.rst + prev_whats_new/github_stats_3.10.1.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/release/release_notes_next.rst b/doc/release/release_notes_next.rst new file mode 100644 index 000000000000..de10d5e8dc27 --- /dev/null +++ b/doc/release/release_notes_next.rst @@ -0,0 +1,12 @@ +.. redirect-from:: /users/release_notes_next + +:orphan: + +Next version +============ +.. toctree:: + :maxdepth: 1 + + next_whats_new + ../api/next_api_changes + github_stats diff --git a/doc/resources/index.rst b/doc/resources/index.rst deleted file mode 100644 index 99077fc0ef68..000000000000 --- a/doc/resources/index.rst +++ /dev/null @@ -1,55 +0,0 @@ -.. _resources-index: - -******************* - External Resources -******************* - - -============================= - Books, Chapters and Articles -============================= - -* `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 - -* `Ten Simple Rules for Better Figures - `_ - by Nicolas P. Rougier, Michael Droettboom and Philip E. Bourne - -======= - 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..95ebf86b5193 --- /dev/null +++ b/doc/sphinxext/gallery_order.py @@ -0,0 +1,137 @@ +""" +Configuration for the order of gallery sections and examples. +Paths are relative to the conf.py file. +""" + +import itertools +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** + # animation + "simple_anim", # Most basic example + # 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 + +_preserve_count = itertools.count() + + +def preserve_order(item): + """A sorting key to preserve the original order of items in minigalleries.""" + return next(_preserve_count) 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/rcparams.py b/doc/sphinxext/rcparams.py new file mode 100644 index 000000000000..71bffe83a40c --- /dev/null +++ b/doc/sphinxext/rcparams.py @@ -0,0 +1,50 @@ +from docutils.parsers.rst import Directive + +from matplotlib import rcsetup + + +class RcParamsDirective(Directive): + has_content = False + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = {} + + def run(self): + """ + Generate rst documentation for rcParams. + + Note: The style is very simple, but will be refined later. + """ + self.state.document.settings.env.note_dependency(__file__) + self.state.document.settings.env.note_dependency(rcsetup.__file__) + lines = [] + for elem in rcsetup._DEFINITION: + if isinstance(elem, (rcsetup._Section, rcsetup._Subsection)): + title_char = '-' if isinstance(elem, rcsetup._Section) else '~' + lines += [ + '', + elem.title, + title_char * len(elem.title), + '', + elem.description or "", + '', + ] + elif isinstance(elem, rcsetup._Param): + if elem.name[0] == '_': + continue + lines += [ + f'.. _rcparam_{elem.name.replace(".", "_")}:', + '', + f'{elem.name}: ``{elem.default!r}``', + f' {elem.description if elem.description else "*no description*"}' + ] + self.state_machine.insert_input(lines, 'rcParams table') + return [] + + +def setup(app): + app.add_directive("rcparams", RcParamsDirective) + + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} + return metadata diff --git a/doc/sphinxext/redirect_from.py b/doc/sphinxext/redirect_from.py new file mode 100644 index 000000000000..329352b3a3c8 --- /dev/null +++ b/doc/sphinxext/redirect_from.py @@ -0,0 +1,132 @@ +""" +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 + and domain.redirects[redirected_reldoc] != current_doc + ): + raise ValueError( + f"{redirected_reldoc} is already noted as redirecting to " + f"{domain.redirects[redirected_reldoc]}\n" + f"Cannot also redirect it to {current_doc}" + ) + 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/util.py b/doc/sphinxext/util.py new file mode 100644 index 000000000000..c0f336eaea18 --- /dev/null +++ b/doc/sphinxext/util.py @@ -0,0 +1,53 @@ +import sys + +from sphinx_gallery import gen_rst + + +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) + + +# Monkey-patching gallery header to include search keywords +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}: + +""" + + +def patch_header(gallery_conf, fname): + gen_rst.EXAMPLE_HEADER = EXAMPLE_HEADER 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 b1e0e9476b02..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 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. - -.. 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..5aec1e08fb14 --- /dev/null +++ b/doc/users/faq.rst @@ -0,0 +1,405 @@ +.. _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 its background patch." The exception for the background is +necessary, because by default every figure contains a `.Rectangle` as its +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. +Whether or not something has been added to the figure is usually defined +within the context of the program. + +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 +---------------------------------------------- + +The recommended approach since Matplotlib 3.1 is to explicitly create a Figure +instance:: + + from matplotlib.figure import Figure + fig = Figure() + ax = fig.subplots() + ax.plot([1, 2, 3]) + fig.savefig('myfig.png') + +This prevents any interaction with GUI frameworks and the window manager. + +It's alternatively still possible to use the pyplot interface: instead of +calling `matplotlib.pyplot.show`, call `matplotlib.pyplot.savefig`. In that +case, you must close the figure after saving it. Not closing the figure causes +a memory leak, because pyplot keeps references to all not-yet-shown figures. :: + + 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/getting_started/index.rst b/doc/users/getting_started/index.rst new file mode 100644 index 000000000000..dfbbd615b5cd --- /dev/null +++ b/doc/users/getting_started/index.rst @@ -0,0 +1,36 @@ +Getting started +=============== + +Installation quick-start +------------------------ + +.. include:: /install/quick_install.inc.rst + +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 deleted file mode 100644 index 92de488b4380..000000000000 --- a/doc/users/github_stats.rst +++ /dev/null @@ -1,1250 +0,0 @@ - -.. _github-stats: - -Github stats -============ - -GitHub stats for 2013/07/31 - 2014/10/25 (tag: v1.3.0) - -These lists are automatically generated, and may be incomplete or contain duplicates. - -The following 190 authors contributed 3221 commits. - -* Adam Heck -* Adrian Price-Whelan -* Alex Loew -* Alistair Muldal -* Andrea Bedini -* Andreas Wallner -* Andrew Dawson -* Andrew Merrill -* 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 -* 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 -* 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 - -We closed 459 issues and merged 579 pull requests; -this is the full list (generated with the script -:file:`tools/github_stats.py`): - -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 - -Issues (579): - -* :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' diff --git a/doc/users/glossary.rst b/doc/users/glossary.rst new file mode 100644 index 000000000000..8a2a3fd96bd1 --- /dev/null +++ b/doc/users/glossary.rst @@ -0,0 +1,44 @@ +======== +Glossary +======== + +.. Note for glossary authors: + The glossary is primarily intended for Matplotlib's own concepts and + terminology, e.g. figure, artist, backend, etc. We don't want to list + general terms like "GUI framework", "event loop" or similar. + The glossary should contain a short definition of the term, aiming at + a high-level understanding. Use links to redirect to more comprehensive + explanations and API reference when possible. + +This glossary defines concepts and terminology specific to Matplotlib. + +.. glossary:: + + Figure + The outermost container for a Matplotlib graphic. Think of this as the + canvas to draw on. + + This is implemented in the class `.Figure`. For more details see + :ref:`figure-intro`. + + Axes + This is a container for what is often colloquially called a plot/chart/graph. + It's a data area with :term:`Axis`\ es, i.e. coordinate directions, + and includes data artists like lines, bars etc. as well as + decorations like title, axis labels, legend. + + Since most "plotting operations" are realized as methods on `~.axes.Axes` + this is the object users will mostly interact with. + + Note: The term *Axes* was taken over from MATLAB. Think of this as + a container spanned by the *x*- and *y*-axis, including decoration + and data. + + Axis + A direction with a scale. The scale defines the mapping from + data coordinates to screen coordinates. The Axis also includes + the ticks and axis label. + + Artist + The base class for all graphical element that can be drawn. + Examples are Lines, Rectangles, Text, Ticks, Legend, Axes, ... 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 abf79517c782..000000000000 --- a/doc/users/image_tutorial.rst +++ /dev/null @@ -1,384 +0,0 @@ -.. _image_tutorial: - - -************** -Image tutorial -************** - -.. _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 at a shell, or the IPython Notebook now. - -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 IPython 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 color map is not possible from cells below the cell that creates a plot. -However, for other backends, such as qt4, 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 imperative-style 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 object-oriented interface, which is also -very powerful, and generally more suitable for large application -development. If you'd like to learn about the object-oriented -interface, a great place to start is our `FAQ on usage -`_. For now, let's get on -with the imperative-style approach: - -.. sourcecode:: ipython - - In [2]: import matplotlib.pyplot as plt - In [3]: import matplotlib.image as mpimg - In [4]: import numpy as np - -.. _importing_data: - -Importing image data into Numpy arrays -=============================================== - -Loading image data is supported by the `Pillow -`_ library. 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 [5]: img=mpimg.imread('stinkbug.png') - Out[5]: - 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.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 [6]: 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. - -.. _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 [7]: lum_img = img[:,:,0] - -This is array slicing. You can read more in the `Numpy tutorial -`_. - -.. sourcecode:: ipython - - In [8]: 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 (2D, no color) image, the default colormap (aka lookup table, -LUT), is applied. The default is called jet. There are plenty of -others to choose from. - -.. sourcecode:: ipython - - In [9]: plt.imshow(lum_img, 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') - -Note that you can also change colormaps on existing plot objects using the -:meth:`~matplotlib.image.Image.set_cmap` method: - -.. sourcecode:: ipython - - In [10]: imgplot = plt.imshow(lum_img) - In [11]: 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') - -.. note:: - - However, remember that in the IPython 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 `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. - -.. sourcecode:: ipython - - In [12]: imgplot = plt.imshow(lum_img) - In [13]: 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 [14]: plt.hist(lum_img.ravel(), bins=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='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 passing the clim argument to -imshow. You could also do this by calling the -:meth:`~matplotlib.image.Image.set_clim` method of the image plot -object, but make sure that you do so in the same cell as your plot -command when working with the IPython Notebook - it will not change -plots from earlier cells. - -.. sourcecode:: ipython - - In [15]: imgplot = plt.imshow(lum_img, 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. - -We'll use the Pillow library that we used to load the image also to resize -the image. - -.. sourcecode:: ipython - - In [16]: from PIL import Image - In [17]: img = Image.open('../_static/stinkbug.png') - In [18]: resized = img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place - In [19]: imgplot = plt.imshow(img) - -.. plot:: - - import matplotlib.pyplot as plt - from PIL import Image - img = Image.open('../_static/stinkbug.png') # opens the file using Pillow - it's not an array yet - img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place - imgplot = plt.imshow(img) - -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 [20]: imgplot = plt.imshow(resized, interpolation="nearest") - -.. plot:: - - import matplotlib.pyplot as plt - from PIL import Image - img = Image.open('../_static/stinkbug.png') # opens the file using Pillow - it's not an array yet - img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place - imgplot = plt.imshow(img, interpolation="nearest") - -.. sourcecode:: ipython - - In [21]: imgplot = plt.imshow(resized, interpolation="bicubic") - -.. plot:: - - import matplotlib.pyplot as plt - from PIL import Image - img = Image.open('../_static/stinkbug.png') # opens the file using Pillow - it's not an array yet - img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place - 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/doc/users/index.rst b/doc/users/index.rst index eca6241e139e..b98bda824a7e 100644 --- a/doc/users/index.rst +++ b/doc/users/index.rst @@ -1,26 +1,107 @@ + .. _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/configuration + 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 + glossary 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/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 c94a8be4b45a..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. -''' -from __future__ import print_function -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 range(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 range(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 range(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 range(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 44bcef224094..000000000000 --- a/doc/users/plotting/colormaps/grayscale.py +++ /dev/null @@ -1,84 +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', ['Blues', 'BuGn', 'BuPu', - 'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd', - 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', - 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']), - ('Sequential (2)', ['afmhot', 'autumn', 'bone', 'cool', 'copper', - 'gist_heat', 'gray', 'hot', 'pink', - 'spring', 'summer', 'winter']), - ('Diverging', ['BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr', - 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'Spectral', - 'seismic']), - ('Qualitative', ['Accent', 'Dark2', 'Paired', 'Pastel1', - 'Pastel2', 'Set1', 'Set2', 'Set3']), - ('Miscellaneous', ['gist_earth', 'terrain', 'ocean', 'gist_stern', - 'brg', 'CMRmap', 'cubehelix', - 'gnuplot', 'gnuplot2', 'gist_ncar', - 'nipy_spectral', 'jet', 'rainbow', - 'gist_rainbow', 'hsv', '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 2fe0721b688a..000000000000 --- a/doc/users/plotting/colormaps/lightness.py +++ /dev/null @@ -1,130 +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', ['Blues', 'BuGn', 'BuPu', - 'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd', - 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', - 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']), - ('Sequential (2)', ['afmhot', 'autumn', 'bone', 'cool', 'copper', - 'gist_heat', 'gray', 'hot', 'pink', - 'spring', 'summer', 'winter']), - ('Diverging', ['BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr', - 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'Spectral', - 'seismic']), - ('Qualitative', ['Accent', 'Dark2', 'Paired', 'Pastel1', - 'Pastel2', 'Set1', 'Set2', 'Set3']), - ('Miscellaneous', ['gist_earth', 'terrain', 'ocean', 'gist_stern', - 'brg', 'CMRmap', 'cubehelix', - 'gnuplot', 'gnuplot2', 'gist_ncar', - 'nipy_spectral', 'jet', 'rainbow', - 'gist_rainbow', 'hsv', '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 12 colormaps - dsub = 6 - elif cmap_category == 'Sequential (2)': - dsub = 6 - 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(range(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=='Sequential (2)': - dc = 1.15 - ax.scatter(x+j*dc, lab[0,:,0], c=x, cmap=cmap, s=300, linewidths=0.) - 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.) - ax.axis([-0.1,7.1,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 e1fbaf5c5f99..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 range(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/pyplot_tutorial.rst b/doc/users/pyplot_tutorial.rst deleted file mode 100644 index f13ca6d37621..000000000000 --- a/doc/users/pyplot_tutorial.rst +++ /dev/null @@ -1,301 +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`. - - -Logarithmic and other nonlinear axis -==================================== - -: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. - -.. plot:: pyplots/pyplot_scales.py - :include-source: - -It is also possible to add your own scale, see :ref:`adding-new-scales` for -details. 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/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 06339961ed92..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 ``mpl_configdir/stylelib`, you can reuse 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. 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. - -For example, you might want to create -``mpl_configdir/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 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 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 f3dfbb720e89..000000000000 --- a/doc/users/whats_new.rst +++ /dev/null @@ -1,1740 +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. - -New backend selection ---------------------- - -The environment variable :envvar:`MPLBACKEND` can now be used to set the -matplotlib backend. - -New ``close-figs`` argument for plot directive ----------------------------------------------- - -Matplotlib has a sphinx extension ``plot_directive`` that creates plots for -inclusion in sphinx documents. Matplotlib 1.5 adds a new option to the plot -directive - ``close-figs`` - that closes any previous figure windows before -creating the plots. This can help avoid some surprising duplicates of plots -when using ``plot_directive``. - -.. _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/images/svg_histogram.svg b/galleries/examples/user_interfaces/images/svg_histogram.svg new file mode 100644 index 000000000000..9e9df77aef15 --- /dev/null +++ b/galleries/examples/user_interfaces/images/svg_histogram.svg @@ -0,0 +1,301 @@ + + + + + + 2026-03-25T12:33:41.331892 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + −3 + + + + + + + + + + −2 + + + + + + + + + + −1 + + + + + + + + + + 0 + + + + + + + + + + 1 + + + + + + + + + + 2 + + + + + + + + + + 3 + + + + + + + + + + + + + + + 0 + + + + + + + + + + 5 + + + + + + + + + + 10 + + + + + + + + + + 15 + + + + + + + + + + 20 + + + + + + + + + + 25 + + + + + + + + + + + + + + + + + From a web browser, click on the legend + marker to toggle the corresponding histogram. + + + + + + + Rabbits + + + + + + Frogs + + + + + + + + + + \ No newline at end of file diff --git a/galleries/examples/user_interfaces/images/svg_tooltip.svg b/galleries/examples/user_interfaces/images/svg_tooltip.svg new file mode 100644 index 000000000000..dd11c2d7782e --- /dev/null +++ b/galleries/examples/user_interfaces/images/svg_tooltip.svg @@ -0,0 +1,385 @@ + + + + + + 2026-03-25T12:36:20.674869 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file 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..8321405aa011 --- /dev/null +++ b/galleries/examples/user_interfaces/mpl_with_glade3_sgskip.py @@ -0,0 +1,53 @@ +""" +======================= +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..967cb7a38779 --- /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 + +from PIL import Image +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 + photo = Image.open(cbook.get_sample_data("grace_hopper.jpg")) + 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..de114cebfbda --- /dev/null +++ b/galleries/examples/user_interfaces/svg_histogram_sgskip.py @@ -0,0 +1,160 @@ +""" +============= +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 + +""" +# sphinx_gallery_thumbnail_path = '_static/svg_histogram.svg' + + +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..86a8088adf04 --- /dev/null +++ b/galleries/examples/user_interfaces/svg_tooltip_sgskip.py @@ -0,0 +1,110 @@ +""" +=========== +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 +""" +# sphinx_gallery_thumbnail_path = '_static/svg_tooltip.svg' + + +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..2e03c5af17c1 --- /dev/null +++ b/galleries/examples/user_interfaces/toolmanager_sgskip.py @@ -0,0 +1,93 @@ +""" +============ +Tool Manager +============ + +This example demonstrates how to + +* modify the Toolbar +* create tools +* add tools +* remove tools + +using `matplotlib.backend_managers.ToolManager`. +""" +# sphinx_gallery_thumbnail_path = '_static/toolmanager.png' + +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..f125916db54b --- /dev/null +++ b/galleries/examples/user_interfaces/web_application_server_sgskip.py @@ -0,0 +1,66 @@ +""" +========================================= +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 +`~.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 `_: +# run +# +# .. code-block:: console +# +# flask --app web_application_server_sgskip run +# +# from the directory containing this script. +# +# +# 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/widgets/GALLERY_HEADER.rst b/galleries/examples/widgets/GALLERY_HEADER.rst new file mode 100644 index 000000000000..aaa2eca9f53c --- /dev/null +++ b/galleries/examples/widgets/GALLERY_HEADER.rst @@ -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..2aef798399f4 --- /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..9123c31f63f4 --- /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((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..c1d7fa667a47 --- /dev/null +++ b/galleries/examples/widgets/radio_buttons.py @@ -0,0 +1,98 @@ +""" +============= +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 + +FREQUENCIES = {'1 Hz': 1, '2 Hz': 2, '4 Hz': 4} + +t = np.arange(0.0, 2.0, 0.01) + + +def f(t, freq): + return np.sin(2 * np.pi * freq * t) + +fig, axd = plt.subplot_mosaic( + [ + ['main', 'freq'], + ['main', 'color'], + ['main', 'linestyle'], + ], + width_ratios=[5, 1], + layout='constrained', +) +(line,) = axd['main'].plot(t, f(t, freq=1), lw=2, color='red') +axd['main'].set(xlabel="Time (s)", ylabel="Amplitude", title="Sine Wave") + +background_color = '0.95' +edge_color = '0.8' + +axd['freq'].set_facecolor(background_color) +axd['freq'].spines[:].set_color(edge_color) +axd['freq'].set_title('Frequency') +radio = RadioButtons(axd['freq'], labels=list(FREQUENCIES.keys()), + label_props={'fontsize': [12, 14, 16]}, + radio_props={'s': [16, 32, 64]}) + + +def update_frequency(label): + ydata = f(t, freq=FREQUENCIES[label]) + line.set_ydata(ydata) + fig.canvas.draw() +radio.on_clicked(update_frequency) + + +axd['color'].set_facecolor(background_color) +axd['color'].spines[:].set_color(edge_color) +axd['color'].set_title('Color') +radio2 = RadioButtons( + axd['color'], ('red', 'blue', 'green'), + label_props={'color': ['red', 'blue', 'green']}, + radio_props={ + 'facecolor': ['red', 'blue', 'green'], + 'edgecolor': ['darkred', 'darkblue', 'darkgreen'], + }) + + +def update_color(label): + line.set_color(label) + fig.canvas.draw() +radio2.on_clicked(update_color) + + +axd['linestyle'].set_facecolor(background_color) +axd['linestyle'].spines[:].set_color(edge_color) +axd['linestyle'].set_title('Linestyle') +radio3 = RadioButtons(axd['linestyle'], ('solid', 'dashed', 'dashdot', 'dotted')) + + +def update_linestyle(label): + line.set_linestyle(label) + fig.canvas.draw() +radio3.on_clicked(update_linestyle) + +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/radio_buttons_grid.py b/galleries/examples/widgets/radio_buttons_grid.py new file mode 100644 index 000000000000..6bb230083729 --- /dev/null +++ b/galleries/examples/widgets/radio_buttons_grid.py @@ -0,0 +1,70 @@ +""" +================== +Radio Buttons Grid +================== + +Using radio buttons in a 2D grid layout. + +Radio buttons can be arranged in a 2D grid by passing a ``(rows, cols)`` +tuple to the *layout* parameter. This is useful when you have multiple +related options that are best displayed in a grid format rather than a +vertical list. + +In this example, we create a color picker using a 2D grid of radio buttons +to select the line color of a plot. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import RadioButtons + +# Generate sample data +t = np.arange(0.0, 2.0, 0.01) +s = np.sin(2 * np.pi * t) + +fig, (ax, ax_buttons) = plt.subplots( + 1, + 2, + figsize=(8, 4), + width_ratios=[4, 1.4], +) + +# Create initial plot +(line,) = ax.plot(t, s, lw=2, color="red") +ax.set(xlabel="Time (s)", ylabel="Amplitude", title="Sine Wave - Click a color!") + +# Configure the radio buttons axes +ax_buttons.set_facecolor("0.95") +ax_buttons.spines[:].set_color("0.8") +ax_buttons.set_title("Line Color") +# Create a 2D grid of color options (3 rows x 2 columns) +colors = ["red", "yellow", "green", "purple", "brown", "gray"] +radio = RadioButtons(ax_buttons, colors, layout=(3, 2)) + + +def update_color(label): + """Update the line color based on selected button.""" + line.set_color(label) + fig.canvas.draw() +radio.on_clicked(update_color) + + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.RadioButtons` +# +# .. tags:: +# +# styling: color +# styling: conditional +# plot-type: line +# level: intermediate +# purpose: showcase diff --git a/galleries/examples/widgets/range_slider.py b/galleries/examples/widgets/range_slider.py new file mode 100644 index 000000000000..d2f2d1554246 --- /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..e56390c182a0 --- /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..5826be32fa07 --- /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..2121ce8594ce --- /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/GALLERY_HEADER.rst b/galleries/plot_types/3D/GALLERY_HEADER.rst new file mode 100644 index 000000000000..61b2729dfb8f --- /dev/null +++ b/galleries/plot_types/3D/GALLERY_HEADER.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/GALLERY_HEADER.rst b/galleries/plot_types/GALLERY_HEADER.rst new file mode 100644 index 000000000000..0bcbb3b804d7 --- /dev/null +++ b/galleries/plot_types/GALLERY_HEADER.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/GALLERY_HEADER.rst b/galleries/plot_types/arrays/GALLERY_HEADER.rst new file mode 100644 index 000000000000..aba457a69940 --- /dev/null +++ b/galleries/plot_types/arrays/GALLERY_HEADER.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/GALLERY_HEADER.rst b/galleries/plot_types/basic/GALLERY_HEADER.rst new file mode 100644 index 000000000000..937c7484c8db --- /dev/null +++ b/galleries/plot_types/basic/GALLERY_HEADER.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/GALLERY_HEADER.rst b/galleries/plot_types/stats/GALLERY_HEADER.rst new file mode 100644 index 000000000000..56a56cb2db04 --- /dev/null +++ b/galleries/plot_types/stats/GALLERY_HEADER.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/GALLERY_HEADER.rst b/galleries/plot_types/unstructured/GALLERY_HEADER.rst new file mode 100644 index 000000000000..89b7924dd2f4 --- /dev/null +++ b/galleries/plot_types/unstructured/GALLERY_HEADER.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..4f93f7c71a6e --- /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/coding_shortcuts.py b/galleries/tutorials/coding_shortcuts.py new file mode 100644 index 000000000000..46868482598f --- /dev/null +++ b/galleries/tutorials/coding_shortcuts.py @@ -0,0 +1,172 @@ +""" +================ +Coding shortcuts +================ + +Matplotlib's primary and universal API is the :ref:`Axes interface `. +While it is clearly structured and powerful, it can sometimes feel overly verbose and +thus cumbersome to write. This page collects patterns for condensing the code +of the Axes-based API and achieving the same results with less typing for many simpler +plots. + +.. note:: + + The :ref:`pyplot interface ` is an alternative more compact + interface, and was historically modeled to be similar to MATLAB. It remains a + valid approach for those who want to use it. However, it has the disadvantage that + it achieves its brevity through implicit assumptions that you have to understand. + + Since it follows a different paradigm, switching between the Axes interface and + the pyplot interface requires a shift of the mental model, and some code rewrite, + if the code develops to a point at which pyplot no longer provides enough + flexibility. + +This tutorial goes the other way round, starting from the standard verbose Axes +interface and using its capabilities for shortcuts when you don't need all the +generality. + +Let's assume we want to make a plot of the number of daylight hours per day over the +year in London. + +The standard approach with the Axes interface looks like this. +""" + +import matplotlib.pyplot as plt +import numpy as np + +day = np.arange(365) +hours = 4.276 * np.sin(2 * np.pi * (day - 80)/365) + 12.203 + +fig, ax = plt.subplots() +ax.plot(day, hours, color="orange") +ax.set_xlabel("day") +ax.set_ylabel("daylight hours") +ax.set_title("London") +plt.show() + +# %% +# Note that we've included ``plt.show()`` here. This is needed to show the plot window +# when running from a command line or in a Python script. If you run a Jupyter notebook, +# this command is automatically executed at the end of each cell. +# +# For the rest of the tutorial, we'll assume that we are in a notebook and leave this +# out for brevity. Depending on your context you may still need it. +# +# If you instead want to save to a file, use ``fig.savefig("daylight.png")``. +# +# +# Collect Axes properties into a single ``set()`` call +# ==================================================== +# +# The properties of Matplotlib Artists can be modified through their respective +# ``set_*()`` methods. Artists additionally have a generic ``set()`` method, that takes +# keyword arguments and is equivalent to calling all the respective ``set_*()`` methods. +# :: +# +# ax.set_xlabel("day") +# ax.set_ylabel("daylight hours") +# +# can also be written as :: +# +# ax.set(xlabel="day", ylabel="daylight hours") +# +# This is the most simple and effective reduction you can do. With that we can shorten +# the above plot to + +fig, ax = plt.subplots() +ax.plot(day, hours, color="orange") +ax.set(xlabel="day", ylabel="daylight hours", title="London") + +# %% +# +# This works as long as you only need to pass one parameter to the ``set_*()`` function. +# The individual functions are still necessary if you want more control, e.g. +# ``set_title("London", fontsize=16)``. +# +# +# Not storing a reference to the figure +# ===================================== +# Another nuisance of ``fig, ax = plt.subplots()`` is that you always create a ``fig`` +# variable, even if you don't use it. A slightly shorter version would be using the +# standard variable for unused value in Python (``_``): ``_, ax = plt.subplots()``. +# However, that's only marginally better. +# +# You can work around this by separating figure and Axes creation and chaining them :: +# +# ax = plt.figure().add_subplot() +# +# This is a bit cleaner logically and has the slight advantage that you could set +# figure properties inline as well; e.g. ``plt.figure(facecolor="lightgoldenrod")``. +# But it has the disadvantage that it's longer than ``fig, ax = plt.subplots()``. +# +# You can still obtain the figure from the Axes if needed, e.g. :: +# +# ax.figure.savefig("daylight_hours.png") +# +# The example code now looks like this: + +ax = plt.figure().add_subplot() +ax.plot(day, hours, color="orange") +ax.set(xlabel="day", ylabel="daylight hours", title="London") + +# %% +# Define Axes properties during axes creation +# =========================================== +# The ``set_*`` methods as well as ``set`` modify existing objects. You can +# alternatively define them right at creation. Since you typically don't instantiate +# classes yourself in Matplotlib, but rather call some factory function that creates +# the object and wires it up correctly with the plot, this may seem less obvious. But +# in fact you just pass the desired properties to the factory functions. You are likely +# doing this already in some places without realizing. Consider the function to create +# a line :: +# +# ax.plot(x, y, color="orange") +# +# This is equivalent to :: +# +# line, = ax.plot(x, y) +# line.set_color("orange") +# +# The same can be done with functions that create Axes. + +ax = plt.figure().add_subplot(xlabel="day", ylabel="daylight hours", title="London") +ax.plot(day, hours, color="orange") + +# %% +# .. important:: +# The Axes properties are only accepted as keyword arguments by +# `.Figure.add_subplot`, which creates a single Axes. +# +# For `.Figure.subplots` and `.pyplot.subplots`, you'd have to pass the properties +# as a dict via the keyword argument ``subplot_kw``. The limitation here is that +# such parameters are given to all Axes. For example, if you need two subplots +# (``fig, (ax1, ax2) = plt.subplots(1, 2)``) with different labels, you have to +# set them individually. +# +# Defining Axes properties during creation is best used for single subplots or when +# all subplots share the same properties. +# +# +# Using implicit figure creation +# ============================== +# You can go even further by tapping into the pyplot logic and use `.pyplot.axes` to +# create the axes: + +ax = plt.axes(xlabel="day", ylabel="daylight hours", title="London") +ax.plot(day, hours, color="orange") + +# %% +# .. warning:: +# When using this, you have to be aware of the implicit figure semantics of pyplot. +# ``plt.axes()`` will only create a new figure if no figure exists. Otherwise, it +# will add the Axes to the current existing figure, which is likely not what you +# want. +# +# Not storing a reference to the Axes +# =================================== +# If you only need to visualize one dataset, you can append the plot command +# directly to the Axes creation. This may be useful e.g. in notebooks, +# where you want to create a plot with some configuration, but as little distracting +# code as possible: + +plt.axes(xlabel="day", ylabel="daylight hours").plot(day, hours, color="orange") diff --git a/galleries/tutorials/images.py b/galleries/tutorials/images.py new file mode 100644 index 000000000000..6c4e68c32416 --- /dev/null +++ b/galleries/tutorials/images.py @@ -0,0 +1,207 @@ +""" +.. redirect-from:: /tutorials/introductory/images + +.. _image_tutorial: + +============== +Image tutorial +============== + +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') + +# %% +# +# 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. + +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..52862a252fcd --- /dev/null +++ b/galleries/tutorials/index.rst @@ -0,0 +1,87 @@ +.. _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 `. + +.. minigallery:: + ../galleries/tutorials/pyplot.py + ../galleries/tutorials/coding_shortcuts.py + ../galleries/tutorials/images.py + ../galleries/tutorials/lifecycle.py + ../galleries/tutorials/artists.py + +.. toctree:: + :hidden: + + /tutorials/pyplot + /tutorials/coding_shortcuts + /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..d932021726da --- /dev/null +++ b/galleries/tutorials/lifecycle.py @@ -0,0 +1,250 @@ +""" +.. 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. + +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/GALLERY_HEADER.rst b/galleries/users_explain/animations/GALLERY_HEADER.rst new file mode 100644 index 000000000000..a7d37a0242e6 --- /dev/null +++ b/galleries/users_explain/animations/GALLERY_HEADER.rst @@ -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..45c42f538fa6 --- /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 an 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..58170fad5b58 --- /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 axes, we'll plot with the default cycler. On the second axes, 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..a6daa3a541c1 --- /dev/null +++ b/galleries/users_explain/artists/imshow_extent.py @@ -0,0 +1,266 @@ +""" +.. redirect-from:: /tutorials/intermediate/imshow_extent + +.. _imshow_extent: + +Positioning and orientation of `~.Axes.imshow` images +===================================================== + +: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..30880f5c907a --- /dev/null +++ b/galleries/users_explain/artists/transforms_tutorial.py @@ -0,0 +1,583 @@ +""" +.. 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". | | +| | | | +| |"Display units" depends on the | | +| |backend. For example, Agg uses | | +| |pixels, and SVG/PDF use points. | | ++----------------+-----------------------------------+-----------------------------+ + +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, there are some more pieces to consider, in +# particular the projection transformation. For example, the ``transData`` +# of `matplotlib.projections.polar.PolarAxes` is more complex than that of a +# typical separable Axes:: +# +# self.transData = ( +# self.transScale + self.transShift + self.transProjection + +# (self.transProjectionAffine + self.transWedge + self.transAxes)) +# +# ``transProjection`` handles the projection from data coordinates +# (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..64879d4a696d --- /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..22cdd1f8dc96 --- /dev/null +++ b/galleries/users_explain/axes/autoscale.py @@ -0,0 +1,320 @@ +""" +.. redirect-from:: /tutorials/intermediate/autoscale + +.. _autoscale: + +Axis autoscaling +================ + +Basic concept +------------- + +Autoscaling ensures that data is visible within the Axes by automatically adjusting +the axis limits. When you plot data, Matplotlib's autoscaling mechanism updates the +axis limits accordingly. +""" + +import matplotlib.pyplot as plt +import numpy as np + + +x = np.linspace(-6, 6, 201) +y = np.sinc(x) + +fig, ax = plt.subplots() +ax.plot(x, y) + +# %% +# +# .. _autoscale_margins: +# +# Margins +# ------- +# To ensure that the data is not at the very edge of the plot, Matplotlib adds a +# margin around the data limits. Note that the *x* data range in the above plot is +# [-6, 6], but the x-axis limits are slightly wider due to the margin. +# +# The default margin is 5%, defined via +# +# - :rc:`axes.xmargin` +# - :rc:`axes.ymargin` +# - :rc:`axes.zmargin` + +print(ax.get_xmargin(), ax.get_ymargin()) + +# %% +# 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) + +# %% +# +# .. _autoscale_sticky_edges: +# +# 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") + +# %% +# If you don't want automatic updates of the axis limits, either deactivate +# autoscaling with `~.axes.Axes.autoscale` or set the limits +# manually with `~.axes.Axes.set_xlim` / `~.axes.Axes.set_ylim`. +# +# 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. Calling `.Axes.autoscale` will re-enable the autoscaling and +# recalculate the limits to fit all the data. + +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()) + +# %% +# Technical background +# -------------------- +# +# This section explains the internal pipeline that runs when autoscaling +# computes axis limits from data. Understanding the mechanics helps when +# you encounter surprising behaviour or need to update limits manually. +# +# Data limits and view limits +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Matplotlib maintains two sets of limits: +# +# - **Data limits** (`.Axes.dataLim`): the tight bounding box of the raw data. +# - **View limits** (`.Axes.viewLim`): the displayed axis limits. By default, +# computed from the data limits through the autoscaling mechanism outlined +# below, but they can be set independently. View limits can alternatively +# be set explicitly through `~.axes.Axes.set_xlim` / `~.axes.Axes.set_ylim`, +# which also disables autoscaling so that the set limits remain fixed. +# +# The following shows the input and output of this process — ``dataLim`` holds +# the raw data bounds, ``viewLim`` the final displayed axis limits. + + +fig, ax = plt.subplots() +x = np.linspace(-6, 6, 201) +y = np.sin(x) +ax.plot(x, y) +print(f"dataLim x: ({ax.dataLim.x0:.3f}, {ax.dataLim.x1:.3f})") +print(f"dataLim y: ({ax.dataLim.y0:.3f}, {ax.dataLim.y1:.3f})") +print(f"viewLim x: ({ax.viewLim.x0:.3f}, {ax.viewLim.x1:.3f})") +print(f"viewLim y: ({ax.viewLim.y0:.3f}, {ax.viewLim.y1:.3f})") + +# %% +# The x data range is [-6, 6] and the default 5% margin adds roughly 0.6 on +# each side, widening the view to about [-6.6, 6.6]. The same applies to the +# y axis. +# +# Update logic +# ~~~~~~~~~~~~ +# +# Data and view limit updates are handled as separate stages. +# +# **Data limits**: When an artist is added to an Axes through one of the +# plotting methods, the data limits are updated through `.Axes.update_datalim` +# to include the new data. This only ever increases the data limits. It is +# also possible to update `.Axes.dataLim` manually, but this is not common. +# Removal of an artist or change of its data does not trigger any update of +# the data limits, so they can become out of date. In such cases, it is +# necessary to explicitly recompute the data limit through `.Axes.relim`. +# +# **View limits**: When autoscaling is enabled, the view limits are +# automatically computed from the data limit. This update is lazy and only +# triggered when the view limits are queried or drawn, so that they don't have +# to be recomputed for every added artist. This is transparent to the user. +# Explicit changes of the data limits through `.Axes.dataLim` or `.Axes.relim` +# do not trigger an update of the view limits, so they can also become out of +# date. In such cases, it is necessary to explicitly recompute the view limits +# through `.Axes.autoscale_view`. +# +# View limit calculation +# ~~~~~~~~~~~~~~~~~~~~~~ +# +# Given the data limits, the view limits are derived through these steps: +# +# - scale domain clamping +# - margin expansion +# - sticky edge clamping +# - optional limit rounding +# +# Scale domain clamping +# ~~~~~~~~~~~~~~~~~~~~~ +# +# Before margins are applied, the data limits are clipped to the valid domain +# of the axis scale. This matters for scales like log (positive values only) +# and logit (values strictly between 0 and 1): if a bound lies outside the +# domain, it is replaced with a value at the domain boundary. +# +# For this purpose, `.Axes.dataLim` tracks not just the ordinary min/max of +# the data but also ``minpos`` — the smallest strictly positive value seen. +# A log-scale lower bound of zero or less is replaced with ``minpos`` rather +# than the actual minimum, because only positive values can be displayed. +# +# For a logit scale, the upper bound is approximated as ``1 - minpos``, since +# the largest data value below 1 is not tracked separately. This means the +# autoscaled upper limit may include slightly more headroom than necessary +# when the data maximum is well below 1. +# +# Margin expansion +# ~~~~~~~~~~~~~~~~ +# +# The first step is to apply the margins, i.e. widen the view limits beyond the +# data limits so that data is not at the very edge of the plot. Margins are +# specified as a fraction of the data span in screen coordinates so that +# the data-free border area always has the same visual size, irrespective of +# data ranges or axis scales. The margin is applied symmetrically to both sides +# of the data limits, so the view is expanded equally in both directions. +# +# This is illustrated in the following example, where the data limits and +# axis scales are different, but the visual margin is the same in both cases. + +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4)) +fig.suptitle("Margins are visually constant, " + "even with different data limits and axis scales") + +ax1.plot([0, 10], [0, 1]) +ax1.margins(0.2) + +x = np.linspace(1, 20) +ax2.semilogy(x, np.exp(x)) +ax2.margins(0.2) + +# %% +# Sticky edges clamping +# ~~~~~~~~~~~~~~~~~~~~~ +# +# Sticky edges are axis values at which margin expansion is clamped. After +# computing the margin-expanded limits, if an expanded limit would extend +# beyond a sticky edge, it is pulled back to that edge instead. +# +# Artists register sticky edges to prevent blank margins at natural data +# boundaries. `~.Axes.imshow`, for example, registers sticky edges at its +# four pixel boundaries, which is why images fill the Axes by default without +# any surrounding margin (as shown in the :ref:`autoscale_sticky_edges` +# section above). Sticky edges only suppress *outward expansion past the data +# boundary* — they never shrink limits into the data, and negative margins +# are not affected. Setting ``Axes.use_sticky_edges = False`` disables sticky +# edge clamping on that Axes. +# +# Limit rounding +# ~~~~~~~~~~~~~~ +# +# As a final step, the view limits can optionally be expanded outward to the +# nearest "nice" tick position, so that the axis edges coincide with tick +# marks. This is disabled by default, but can be turned on with the +# "round_numbers" mode of :rc:`axes.autolimit_mode`: +# +# - ``'data'`` (default): keep the limits at the margin-expanded values. +# - ``'round_numbers'``: expand the limits outward to the nearest "nice" tick +# position, so the axis edges coincide with tick marks. + +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4)) +ax1.plot([0.3, 4.7], [0.3, 4.7]) +ax1.set_title("autolimit_mode='data' (default)") +with plt.rc_context({'axes.autolimit_mode': 'round_numbers'}): + ax2.plot([0.3, 4.7], [0.3, 4.7]) + ax2.set_title("autolimit_mode='round_numbers'") + ax2.autoscale_view() # force autoscale while round_numbers is active diff --git a/galleries/users_explain/axes/axes_intro.rst b/galleries/users_explain/axes/axes_intro.rst new file mode 100644 index 000000000000..bb3094495026 --- /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..f901c012974a --- /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..5c2749804740 --- /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 axes. +# *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..ec0468fe172d --- /dev/null +++ b/galleries/users_explain/axes/legend_guide.py @@ -0,0 +1,372 @@ +""" +.. redirect-from:: /tutorials/intermediate/legend_guide +.. redirect-from:: /gallery/userdemo/simple_legend01 +.. redirect-from:: /gallery/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/GALLERY_HEADER.rst b/galleries/users_explain/colors/GALLERY_HEADER.rst new file mode 100644 index 000000000000..79f49c523f56 --- /dev/null +++ b/galleries/users_explain/colors/GALLERY_HEADER.rst @@ -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..8b773b4fac42 --- /dev/null +++ b/galleries/users_explain/colors/colormap-manipulation.py @@ -0,0 +1,320 @@ +""" +.. 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() + +# %% +# Colormaps added to the registry can also be deregistered: + +mpl.colormaps.unregister(my_cmap.name) + +# %% +# +# .. 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..66bff534b3b0 --- /dev/null +++ b/galleries/users_explain/colors/colormapnorms.py @@ -0,0 +1,375 @@ +""" + +.. 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() + +# %% +# Using a linear scale on the colormap +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# By default, colorbars adopt the same axis scaling as their associated norm. +# For example, for a `.TwoSlopeNorm`, colormap segments are distributed +# linearly and the colorbar ticks positions are spaced non-linearly (as above, +# and the left-hand colorbar below). To make the tick spacing linear instead, +# you can change the scale by calling ``cb.ax.set_yscale('linear')``, as shown +# in the right-hand colorbar below. The ticks will then be evenly spaced, the +# colormap will appear compressed in the smaller of the two slope regions. + +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4)) +divnorm = colors.TwoSlopeNorm(vmin=-500., vcenter=0, vmax=4000) + +for ax, title in zip([ax1, ax2], + ['Default: Scaled colorbar', 'Linear colorbar spacing']): + pcm = ax.pcolormesh(longitude, latitude, topo, rasterized=True, norm=divnorm, + cmap=terrain_map, shading='auto') + ax.set_aspect(1 / np.cos(np.deg2rad(49))) + ax.set_title(title) + cb = fig.colorbar(pcm, ax=ax, shrink=0.6) + cb.set_ticks(np.arange(-500, 4001, 500)) + +# Set linear scale for the right colorbar +cb.ax.set_yscale('linear') + +# %% +# 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..8c97a6acb810 --- /dev/null +++ b/galleries/users_explain/colors/colormaps.py @@ -0,0 +1,464 @@ +""" +.. 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)', + ['gray', 'bone', 'pink', 'spring', 'summer', 'autumn', + 'winter', 'cool', 'Wistia', 'hot', 'afmhot', 'gist_heat', + 'copper']) + +# %% +# .. admonition:: Discouraged +# +# For backward compatibility we additionally support the following colormap +# names, which are identical to other builtin colormaps. Their use is +# discouraged. Use the suggested replacement instead. +# +# ========= ================================= +# Colormap Use identical replacement instead +# ========= ================================= +# gist_gray gray +# gist_yarg gray_r +# binary gray_r +# ========= ================================= +# +# +# 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', 'okabe_ito', + '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] https://dl.acm.org/doi/10.1109/38.7760 +# .. [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..97a281bf1977 --- /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/configuration.py b/galleries/users_explain/configuration.py new file mode 100644 index 000000000000..3849677b5aee --- /dev/null +++ b/galleries/users_explain/configuration.py @@ -0,0 +1,14 @@ +""" +.. _rcparams_reference: + +Matplotlib configuration - rcParams +=================================== +Matplotlib's configuration parameters (rcParams) control the behavior and +appearance of plots. These parameters are stored in a dict-like variable +called :data:`matplotlib.rcParams` (also accessible via ``plt.rcParams``). + +The following is a comprehensive reference of all available rcParams and their +default values. + +.. rcparams:: +""" diff --git a/galleries/users_explain/customizing.py b/galleries/users_explain/customizing.py new file mode 100644 index 000000000000..948727c6a165 --- /dev/null +++ b/galleries/users_explain/customizing.py @@ -0,0 +1,272 @@ +""" +.. redirect-from:: /users/customizing +.. redirect-from:: /tutorials/introductory/customizing + +.. _customizing: + +===================================================== +Customizing Matplotlib with style sheets and rcParams +===================================================== + +Many aspects of Matplotlib's behavior and default styles can be customized +through the use of rc (runtime configuration) settings. The current values +are stored in `~matplotlib.rcParams`. + +There are three ways to customize Matplotlib, all of which effectively change +`~matplotlib.rcParams`: + +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..c3ac06aa27ab --- /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 are named 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 +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..69f6d61dc563 --- /dev/null +++ b/galleries/users_explain/figure/backends.rst @@ -0,0 +1,360 @@ +.. 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`. + +Backend API versions +-------------------- +Matplotlib aims to maintain backward compatibility on backends. Nevertheless, we +want to be able to evolve the backend API to support new features. Defining backend +API versions will help to communicate which API is supported by a given version of +Matplotlib. + +The following backend API versions exist + +.. list-table:: + :header-rows: 1 + + * - API version + - Supported since + - Description + * - 1.0 + - Matplotlib 3.10 + - This is the starting point for systematic definition of backend versions. + Most of the API will work far back, but there is no benefit in retroactively + uncovering all prior the changes. + * - 1.1 + - Matplotlib 3.11 + - `.RendererBase.draw_path_collection` gained a new optional parameter + *hatchcolor*. The presence of the parameter is inferred by introspection, so + that matplotlib 3.11+ will still work with backends implementing API version + 1.0. + +There is currently no plan to remove support for older API versions. + +.. _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..8b4928eafb52 --- /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 an 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/GALLERY_HEADER.rst b/galleries/users_explain/text/GALLERY_HEADER.rst new file mode 100644 index 000000000000..9046e991c924 --- /dev/null +++ b/galleries/users_explain/text/GALLERY_HEADER.rst @@ -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..5221c6c90e12 --- /dev/null +++ b/galleries/users_explain/text/annotations.py @@ -0,0 +1,934 @@ +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 +.. redirect-from:: /gallery/text_labels_and_annotations/annotate_transform + +.. _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,head_width=1.5,head_angle=90 +# Ellipse ``ellipse`` pad=0.3 +# LArrow ``larrow`` pad=0.3,head_width=1.5,head_angle=90 +# RArrow ``rarrow`` pad=0.3,head_width=1.5,head_angle=90 +# 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 +# +# .. _annotations-bbox: +# +# Using an Artist as an annotation +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# `.AnnotationBbox` uses artists in `.OffsetBox` container artists as the annotations +# and supports positioning these annotations using the same coordinate systems as the +# other annotation methods. For more examples, see +# :doc:`/gallery/text_labels_and_annotations/demo_annotation_box` + +from matplotlib.offsetbox import AnnotationBbox, DrawingArea, OffsetImage +from matplotlib.patches import Annulus + +fig, ax = plt.subplots() + +text = ax.text(.2, .8, "Green!", color='green') + +da = DrawingArea(20, 20) +annulus = Annulus((10, 10), 10, 5, color='tab:green') +da.add_artist(annulus) + +# position annulus relative to text +ab1 = AnnotationBbox(da, xy=(.5, 0), + xybox=(.5, .25), + xycoords=text, + boxcoords=(text, "data"), + arrowprops=dict(arrowstyle="->"), + bboxprops=dict(alpha=0.5)) +ax.add_artist(ab1) + +N = 25 +arr = np.repeat(np.linspace(0, 1, N), N).reshape(N, N) +im = OffsetImage(arr, cmap='Greens') +im.image.axes = ax + +# position gradient relative to text and annulus +ab2 = AnnotationBbox(im, xy=(.5, 0), + xybox=(.75, 0), + xycoords=text, + boxcoords=('data', annulus), + arrowprops=dict(arrowstyle="->"), + bboxprops=dict(alpha=0.5)) +ax.add_artist(ab2) + +# %%%% +# .. _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..40cc9eaa93eb --- /dev/null +++ b/galleries/users_explain/text/fonts.py @@ -0,0 +1,186 @@ +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): + +.. table:: Types of Fonts + + +--------------------------+----------------------------+-------------------------------+ + | Type 1 (PDF with usetex) | Type 3 (PDF/PS) | TrueType (PDF) / Type 42 (PS) | + +==========================+============================+===============================+ + | Old font types introduced by Adobe. | Newer font type introduced by | + | | Apple; commonly used today. | + +--------------------------+----------------------------+-------------------------------+ + | Restricted subset of | Full PostScript language, | Includes a virtual machine | + | PostScript, charstrings | allows embedding arbitrary | that can execute code. | + | are in bytecode. | code. | | + +--------------------------+----------------------------+-------------------------------+ + | Supports font hinting. | Does not support font | Supports font hinting, | + | | hinting. | through the virtual machine. | + +--------------------------+----------------------------+-------------------------------+ + | Subsetted by code in | Subsetted via external module | + | `matplotlib._type1font`. | `fontTools `__. | + +--------------------------+----------------------------+-------------------------------+ + +.. note:: + + Adobe disabled__ support for authoring with Type 1 fonts in January 2023. + Matplotlib uses Type 1 fonts for compatibility with TeX; when the usetex + feature is used with the PDF backend, Matplotlib reads the fonts used by + the TeX engine, which are usually Type 1. + + __ https://helpx.adobe.com/fonts/kb/postscript-type-1-fonts-end-of-support.html + +Matplotlib also provides limited support for OpenType fonts, a newer standard +developed jointly by Adobe and Microsoft; such fonts generally contain a much +larger character set. + +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). + +To keep the output size reasonable while using vector fonts, +Matplotlib embeds only the glyphs that are actually used in the document. +This is known as font subsetting. +Computing the font subset and writing the reduced font are both complex problems, +which Matplotlib solves in most cases by using the +`fontTools `__ library. + +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. +""" # noqa: E501 diff --git a/galleries/users_explain/text/mathtext.py b/galleries/users_explain/text/mathtext.py new file mode 100644 index 000000000000..4a4f80c12695 --- /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:: +# +# '$\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..50eb53dccbdd --- /dev/null +++ b/galleries/users_explain/text/text_props.py @@ -0,0 +1,294 @@ +""" + +.. 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., ``'small'``, ``'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 +========================== ====================================================================================================================== + + +Text alignment +============== + +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 = 0.25, 0.5 +bottom, height = 0.25, 0.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() + +# %% +# Relative font sizes +# =================== +# +# Font sizes can be specified in points, or as a string that indicates the size +# relative to the default font size. The following are valid values for relative font sizes: +# +# ==================== ================================ +# Relative font size Scaling of default font size +# ==================== ================================ +# xx-small 0.579 +# x-small 0.694 +# small 0.833 +# medium 1.000 +# large 1.200 +# x-large 1.440 +# xx-large 1.728 +# ==================== ================================ +# +# +# ============== +# 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..1b770c828ff6 --- /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 an 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), use ``axis.major_ticks.set_ticksize``. + + To change the direction of the ticks, use + ``axis.major_ticks.set_tick_direction``. + + To change the pad between ticks and ticklabels, use + ``axis.major_ticklabels.set_pad``. + + To change the pad between ticklabels and axis label, use + ``axis.label.set_pad``. + +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 `.AxisArtist.invert_ticklabel_direction`:: + + ax.axis[:].invert_ticklabel_direction() + +A related method is `.Ticks.set_tick_direction`. It can make ticks point "in", +"out", or "inout" (crossing the axis halfway):: + + ax.axis[:].major_ticks.set_tick_direction("inout") + +.. 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 + + - `~.AxisArtist.set_axis_direction`: "left", "right", "bottom", or "top" + - `~.AxisArtist.set_ticklabel_direction`: "+" or "-" + - `~.AxisArtist.set_axislabel_direction`: "+" or "-" + - `~.AxisArtist.invert_ticklabel_direction` + +* Ticks' methods (major_ticks and minor_ticks) + + - `~.Ticks.set_tick_direction`: "in", "out", or "inout" + - `~.Ticks.set_ticksize`: size in points + +* TickLabels' methods (major_ticklabels and minor_ticklabels) + + - `~.TickLabels.set_axis_direction`: "left", "right", "bottom", or "top" + - `~.Text.set_rotation`: angle with respect to the reference direction + - `~.Text.set_horizontalalignment` and `~.Text.set_verticalalignment`: see below + +* AxisLabel' methods (label) + + - `~.AxisLabel.set_axis_direction`: "left", "right", "bottom", or "top" + - `~.Text.set_rotation`: angle with respect to the reference direction + - `~.Text.set_horizontalalignment` and + `~.Text.set_verticalalignment` + +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 an 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 an 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 7f806098b7eb..2a83cc1f1091 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,897 +17,808 @@ 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 -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, mplDeprecation -from matplotlib.compat import subprocess -from matplotlib.rcsetup import (defaultParams, - validate_backend) - -import numpy -from six.moves.urllib.request import urlopen -from six.moves import reload_module as reload - -__version__ = str('1.5.dev1') -__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 - - -if not hasattr(sys, 'argv'): # for modpython - sys.argv = [str('modpython')] - - -major, minor1, minor2, s, tmp = sys.version_info -_python26 = (major == 2 and minor1 >= 6) or major >= 3 - -if not _python26: - raise ImportError('matplotlib requires Python 2.6 or later') - - -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, 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: - return False + Parse a version string to a namedtuple analogous to sys.version_info. - return True - - -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 - + 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. -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 + 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. + Matplotlib uses the standard library `logging` framework under the root + logger 'matplotlib'. This is a helper function to: -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 + - set Matplotlib's root logger level + - set the root logger handler's level, creating the handler + if it does not exist yet + Typically, one should call ``set_loglevel("INFO")`` or + ``set_loglevel("DEBUG")`` to get additional debugging information. -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 + Users or applications that are installing their own logging handlers + may want to directly manipulate ``logging.getLogger('matplotlib')`` rather + than use this function. + Parameters + ---------- + level : {"NOTSET", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} + The log level as defined in `Python logging levels + `__. -def checkdep_ps_distiller(s): - if not s: - return False + For backwards compatibility, the levels are case-insensitive, but + the capitalized version is preferred in analogy to `logging.Logger.setLevel`. - 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", timeout=30) + except subprocess.CalledProcessError as _cpe: + if ignore_exit_code: + output = _cpe.output + else: + raise ExecutableNotFoundError(str(_cpe)) from _cpe + except subprocess.TimeoutExpired as _te: + msg = f"Timed out running {cbook._pformat_subprocess(args)}" + raise ExecutableNotFoundError(msg) from _te + 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: - configdir = os.path.abspath(configdir) - if not os.path.exists(configdir): - 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 + 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. + try: + configdir = Path(xdg_base_getter(), "matplotlib") + except RuntimeError: # raised if Path.home() is not available + pass + elif sys.platform == 'win32': + # On Windows, prefer %LOCALAPPDATA%\matplotlib which is the proper + # location for non-roaming application data (cache and config). + # See: https://docs.microsoft.com/en-us/windows/apps/design/app-settings/store-and-retrieve-app-data + # + # However, for backwards compatibility, if the old location + # (%USERPROFILE%\.matplotlib) exists, continue using it so existing + # users don't lose their config. + try: + old_configdir = Path.home() / ".matplotlib" + if old_configdir.is_dir(): + configdir = old_configdir else: - return p - - return _create_tmp_config_dir() - + localappdata = os.environ.get('LOCALAPPDATA') + if localappdata: + configdir = Path(localappdata) / "matplotlib" + else: + configdir = old_configdir + except RuntimeError: # raised if Path.home() is not available + localappdata = os.environ.get('LOCALAPPDATA') + if localappdata: + configdir = Path(localappdata) / "matplotlib" + else: + try: + configdir = Path.home() / ".matplotlib" + except RuntimeError: # raised if Path.home() is not available + pass -def _get_configdir(): + if configdir: + # 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) + issue_msg = "the default path ({configdir})" + else: + issue_msg = "resolving the home directory" + # 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 {issue_msg}, 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 %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, issue_msg) + 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 Windows, + use ``%LOCALAPPDATA%\\matplotlib``. 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 + on Linux. On Windows, uses ``%LOCALAPPDATA%\\matplotlib`` (same as config). """ - 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 +def matplotlib_fname(): + """ + Get the location of the config file. - # 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 + The file location is determined in the following order - raise RuntimeError('Could not find the matplotlib data files') + - ``$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. + """ + 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') -def _get_data_path_cached(): - if defaultParams['datapath'][0] is None: - defaultParams['datapath'][0] = _get_data_path() - return defaultParams['datapath'][0] + for fname in gen_candidates(): + if os.path.exists(fname) and not os.path.isdir(fname): + return fname -get_data_path = verbose.wrap('matplotlib data path %s', _get_data_path_cached, - always=False) + raise RuntimeError("Could not find matplotlibrc file; your Matplotlib " + "install is broken") -def get_example_data(fname): - """ - get_example_data is deprecated -- use matplotlib.cbook.get_sample_data - instead +class RcParams(MutableMapping, dict): """ - 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()) + A dict-like key-value store for config parameters, including validation. + This is the data structure behind `matplotlib.rcParams`. -def matplotlib_fname(): + The complete list of rcParams can be found in :doc:`/users/explain/configuration`. """ - Get the location of the config file. - - The file location is determined in the following order - - - `$PWD/matplotlibrc` - - - environment variable `MATPLOTLIBRC` - - - `$MPLCONFIGDIR/matplotlib` - - - On Linux, - - - `$HOME/.matplotlib/matplotlibrc`, if it exists - - 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 + valid_key = _api.getitem_checked( + self.validate, rcParam=key, _error_cls=KeyError + ) 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 = valid_key(val) + except ValueError as ve: + raise ValueError(f"Key {key}: {ve}") from None + if key in {"text.hinting_factor", "text.kerning_factor"} and cval is not None: + _api.warn_deprecated("3.11", name=key, obj_type="rcParam") + 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): """ @@ -920,133 +831,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) - + return self.__class__( + (key, value) for key, value in self.items() if pattern_re.search(key) + ) -URL_REGEX = re.compile(r'http://|https://|ftp://|file://|file:\\') + def copy(self): + """Copy this RcParams instance.""" + rccopy = self.__class__() + for k in self: # Skip deprecations and revalidation. + rccopy._set(k, self._get(k)) + return rccopy -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 @@ -1054,71 +965,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) + with _api.suppress_matplotlib_deprecation_warning(): + config = RcParams({**rcParamsDefault, **config_from_file}) - verbose.set_level(config['verbose.level']) - verbose.set_fileo(config['verbose.fileo']) - - 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']: 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*). @@ -1126,17 +1021,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' @@ -1144,26 +1038,31 @@ 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:: font = {'family' : 'monospace', 'weight' : 'bold', - 'size' : 'larger'} - + 'size' : 'large'} 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 = { @@ -1174,311 +1073,510 @@ 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. + Update `.rcParams` from file. - This allows one to do:: + Style-blacklisted `.rcParams` (defined in + ``matplotlib.style.core.STYLE_BLACKLIST``) are not updated. - 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) - - 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 + to switch the backend. + 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:]) - warnings.warn("Using the -d command line argument to select a " - "matplotlib backend is deprecated. Please use the " - "MPLBACKEND environment variable instead.", - mplDeprecation) - break - except (KeyError, ValueError): - pass - # we don't want to assume all -d flags are backends, e.g., -debug -else: - # no backend selected from the command line, so we check the environment - # variable MPLBACKEND +def _val_or_rc(val, *rc_names): + """ + If *val* is None, the first not-None value in ``mpl.rcParams[rc_names[i]]``. + If all are None returns ``mpl.rcParams[rc_names[-1]]``. + """ + if val is not None: + return val + + for rc_name in rc_names[:-1]: + if rcParams[rc_name] is not None: + return rcParams[rc_name] + return rcParams[rc_names[-1]] + + +def _init_tests(): + # The version of FreeType to install locally for running the tests. This must match + # the value in `subprojects/freetype2.wrap`. + LOCAL_FREETYPE_VERSION = '2.14.3' + + 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 ") + + # Generate a shortcut for classic testing style. + from matplotlib.style import _base_library, library + _base_library['_classic_test'] = library['_classic_test'] = RcParams( + _base_library['classic'] | _base_library['_classic_test_patch']) + + +def _replacer(data, value): + """ + Either returns ``data[value]`` or passes ``data`` back, converting any + ``MappingView`` to a sequence. + """ try: - use(os.environ['MPLBACKEND']) - except (KeyError, ValueError): + # 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 + return cbook.sanitize_sequence(value) -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_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', - 'matplotlib.tests.test_widgets', - 'matplotlib.sphinxext.tests.test_tinypages', - 'mpl_toolkits.tests.test_mplot3d', - 'mpl_toolkits.tests.test_axes_grid1', - 'mpl_toolkits.tests.test_axes_grid', - ] - - -def test(verbosity=1): - """run the matplotlib test suite""" + +def _label_from_arg(y, default_name): try: - import faulthandler - except ImportError: - pass + 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: - faulthandler.enable() + 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): + __tracebackhide__ = True + + 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) - old_backend = rcParams['backend'] - 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 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..321c5a4b90b2 --- /dev/null +++ b/lib/matplotlib/__init__.pyi @@ -0,0 +1,129 @@ +__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 matplotlib.typing import RcKeyType, RcGroupKeyType +from typing import Any, Literal, NamedTuple, overload +from matplotlib.typing import LogLevel + + +class _VersionInfo(NamedTuple): + major: int + minor: int + micro: int + releaselevel: str + serial: int + +__bibtex__: str +__version__: str +__version_info__: _VersionInfo + +def set_loglevel(level: LogLevel) -> 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[RcKeyType, Any]): + validate: dict[str, Callable] + def __init__(self, *args, **kwargs) -> None: ... + def _set(self, key: RcKeyType, val: Any) -> None: ... + def _get(self, key: RcKeyType) -> Any: ... + + def _update_raw(self, other_params: dict | RcParams) -> None: ... + + def _ensure_has_backend(self) -> None: ... + def __setitem__(self, key: RcKeyType, val: Any) -> None: ... + def __getitem__(self, key: RcKeyType) -> Any: ... + def __iter__(self) -> Generator[RcKeyType, 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[RcKeyType, Any] + +def rc(group: RcGroupKeyType, **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[RcKeyType, 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..af607b0374fc --- /dev/null +++ b/lib/matplotlib/_afm.py @@ -0,0 +1,499 @@ +""" +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. +""" + +import inspect +import logging +import re +from typing import BinaryIO, NamedTuple, TypedDict, cast + +from ._mathtext_data import uni2type1 +from .ft2font import CharacterCodeType, GlyphIndexType + + +_log = logging.getLogger(__name__) + + +def _to_int(x: bytes | str) -> int: + # 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: bytes | str) -> float: + # 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: bytes) -> str: + return x.decode('utf8') + + +def _to_list_of_ints(s: bytes) -> list[int]: + s = s.replace(b',', b' ') + return [_to_int(val) for val in s.split()] + + +def _to_list_of_floats(s: bytes | str) -> list[float]: + return [_to_float(val) for val in s.split()] + + +def _to_bool(s: bytes) -> bool: + if s.lower().strip() in (b'false', b'0', b'no'): + return False + else: + return True + + +class FontMetricsHeader(TypedDict, total=False): + StartFontMetrics: float + FontName: str + FullName: str + FamilyName: str + Weight: str + ItalicAngle: float + IsFixedPitch: bool + FontBBox: list[int] + UnderlinePosition: float + UnderlineThickness: float + Version: 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. + Notice: bytes + EncodingScheme: str + CapHeight: float # Is the second version a mistake, or + Capheight: float # do some AFM files contain 'Capheight'? -JKS + XHeight: float + Ascender: float + Descender: float + StdHW: float + StdVW: float + StartCharMetrics: int + CharacterSet: str + Characters: int + + +def _parse_header(fh: BinaryIO) -> FontMetricsHeader: + """ + 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 = { + bool: _to_bool, + bytes: lambda x: x, + float: _to_float, + int: _to_int, + list[int]: _to_list_of_ints, + str: _to_str, + } + header_value_types = inspect.get_annotations(FontMetricsHeader) + d: FontMetricsHeader = {} + 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: + key_str = _to_str(key) + value_type = header_value_types[key_str] + except (KeyError, UnicodeDecodeError): + _log.error("Found an unknown keyword in AFM header (was %r)", key) + continue + try: + converter = header_converters[value_type] + d[key_str] = converter(val) # type: ignore[literal-required] + except ValueError: + _log.error('Value error parsing header in AFM: %r, %r', key, val) + continue + if key == b'StartCharMetrics': + break + else: + raise RuntimeError('Bad parse') + return d + + +class CharMetrics(NamedTuple): + """ + 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. + """ + + width: float + name: str + bbox: tuple[int, int, int, int] + + +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: BinaryIO) -> tuple[dict[CharacterCodeType, CharMetrics], + dict[str, CharMetrics]]: + """ + 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: dict[CharacterCodeType, CharMetrics] = {} + name_d: dict[str, CharMetrics] = {} + for bline in fh: + # We are defensively letting values be utf8. The spec requires + # ascii, but there are non-compliant fonts in circulation + line = _to_str(bline.rstrip()) + 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 = tuple(map(int, _to_list_of_floats(vals['B']))) + if len(bbox) != 4: + raise RuntimeError(f'Bad parse: bbox has {len(bbox)} elements, should be 4') + 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: BinaryIO) -> dict[tuple[str, str], float]: + """ + 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(f'Bad start of kern pairs data: {line!r}') + + d: dict[tuple[str, str], float] = {} + 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(f'Bad kern pairs line: {line!r}') + 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') + + +class CompositePart(NamedTuple): + """Represents the information on a composite element of a composite char.""" + + name: bytes + dx: float + dy: float + + +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: BinaryIO) -> dict[bytes, list[CompositePart]]: + """ + 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[b'Aacute'] = [CompositePart(name=b'A', dx=0, dy=0), + CompositePart(name=b'acute', dx=160, dy=170)] + + """ + composites: dict[bytes, list[CompositePart]] = {} + 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]) + if len(vals) != _num_parts + 2: # First element is 'CC', last is empty. + raise RuntimeError(f'Bad composites parse: expected {_num_parts} parts, ' + f'but got {len(vals) - 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: BinaryIO) -> tuple[dict[tuple[str, str], float], + dict[bytes, list[CompositePart]]]: + """ + 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`. + """ + kern_data: dict[tuple[str, str], float] = {} + composites: dict[bytes, list[CompositePart]] = {} + for line in fh: + line = line.rstrip() + if not line: + continue + match line.split()[0]: + case b'StartKernData': + kern_data = _parse_kern_pairs(fh) + case b'StartComposites': + composites = _parse_composites(fh) + + return kern_data, composites + + +class AFM: + + def __init__(self, fh: BinaryIO): + """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: str) -> tuple[int, int, float, int, int]: + """Return the string bounding box and the maximal descent.""" + if not len(s): + return 0, 0, 0, 0, 0 + total_width = 0.0 + namelast = '' + miny = 1_000_000_000 + maxy = 0 + left = 0 + 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, # For consistency with FT2Font. + glyph_ind: GlyphIndexType) -> str: + """Get the name of the glyph, i.e., ord(';') is 'semicolon'.""" + return self._metrics[cast(CharacterCodeType, glyph_ind)].name + + def get_char_index(self, # For consistency with FT2Font. + c: CharacterCodeType) -> GlyphIndexType: + """ + 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 cast(GlyphIndexType, c) + + def get_width_char(self, c: CharacterCodeType) -> float: + """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: str) -> float: + """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: str, name2: str) -> float: + """ + Return the kerning pair distance (possibly 0) for chars *name1* and *name2*. + """ + return self._kern.get((name1, name2), 0) + + def get_fontname(self) -> str: + """Return the font name, e.g., 'Times-Roman'.""" + return self._header['FontName'] + + @property + def postscript_name(self) -> str: # For consistency with FT2Font. + return self.get_fontname() + + def get_fullname(self) -> str: + """Return the font full name, e.g., 'Times-Roman'.""" + name = self._header.get('FullName') + if name is None: # use FontName as a substitute + name = self._header['FontName'] + return name + + def get_familyname(self) -> str: + """Return the font family name, e.g., 'Times'.""" + name = self._header.get('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) -> str: # For consistency with FT2Font. + """The font family name, e.g., 'Times'.""" + return self.get_familyname() + + def get_weight(self) -> str: + """Return the font weight, e.g., 'Bold' or 'Roman'.""" + return self._header['Weight'] + + def get_angle(self) -> float: + """Return the fontangle as float.""" + return self._header['ItalicAngle'] + + def get_ascender(self) -> float: + """Return the ascent as float.""" + return self._header['Ascender'] + + def get_capheight(self) -> float: + """Return the cap height as float.""" + return self._header['CapHeight'] + + def get_descender(self) -> float: + """Return the descent as float.""" + return self._header['Descender'] + + def get_xheight(self) -> float: + """Return the xheight as float.""" + return self._header['XHeight'] + + def get_underline_thickness(self) -> float: + """Return the underline thickness as float.""" + return self._header['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..444e9c76b5b3 --- /dev/null +++ b/lib/matplotlib/_api/__init__.py @@ -0,0 +1,494 @@ +""" +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 difflib +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 UnsupportedError(RuntimeError): + """ + Raised on inherited methods if the child class does not support the functionality + of the base class. + + See `.unsupported_method` for details. + """ + + +class unsupported_method: + """ + Descriptor that creates a method raising `.UnsupportedError`. + + Historically, we have quite a few cases of inheritance hierarchies that do not + fully respect the Liskov Substitution Principle, e.g. Axes and Artist. Some of + the methods of a base class may not be implemented in the child class. In that case, + we override the method in the child class to raise `.UnsupportedError`. + + Use in a class body to mark inherited methods as unsupported:: + + class Axes3D(Axes): + twinx = _api.unsupported_method() + + Calling ``Axes3D().twinx()`` will raise + "UnsupportedError: Axes3D does not support 'twinx'." + + Parameters + ---------- + append_message : str + Optional additional text to be appended to the error message. + """ + def __init__(self, *, append_message=None): + self.append_message = append_message + + def __set_name__(self, owner, name): + message = f"{owner.__name__} does not support '{name}'." + if self.append_message: + message += ' ' + self.append_message + + def method(self, *args, **kwargs): + raise UnsupportedError(message) + + method.__name__ = name + method.__qualname__ = f"{owner.__qualname__}.{name}" + method.__module__ = owner.__module__ + setattr(owner, name, method) + + +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 list_suggestion_error_msg(name, potential, values): + """ + Generate an error message that a potential setting is not an acceptable value. + + If the acceptable values are all strings, and sufficiently large, then add just a + few suggestions to the end of the message. Otherwise list the supported values. + + Parameters + ---------- + name : str + The name of the setting, keyword argument, etc. to generate the message for. + potential + The potential value from the user that is not a valid choice. + values : iterable + Sequence of values to check on. + """ + if len(values) > 5 and all(isinstance(v, str) for v in [potential, *values]): + best = difflib.get_close_matches(potential, values, cutoff=0.5) + match len(best): + case 0: + suggestion = "" + case 1: + suggestion = f" Did you mean: {best[0]!r}?" + case _: + suggestion = f" Did you mean one of: {', '.join(map(repr, best))}?" + else: + suggestion = f" Supported values are {', '.join(map(repr, values))}" + return f"{potential!r} is not a valid value for {name}.{suggestion}" + + +def check_in_list(values, /, **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. + + Note: All values must support == comparisons. + This means in particular the entries must not be numpy arrays. + **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(): + try: + exists = val in values + except ValueError: + # `in` internally uses `val == values[i]`. There are some objects + # that do not support == to arbitrary other objects, in particular + # numpy arrays. + # Since such objects are not allowed in values, we can gracefully + # handle the case that val (typically provided by users) is of such + # type and directly state it's not in the list instead of letting + # the individual `val == values[i]` ValueError surface. + exists = False + if not exists: + raise ValueError(list_suggestion_error_msg(key, val, values)) + + +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 getitem_checked(mapping, /, _error_cls=ValueError, **kwargs): + """ + *kwargs* must consist of a single *key, value* pair. If *key* is in + *mapping*, return ``mapping[value]``; else, raise an appropriate + ValueError. + + Parameters + ---------- + _error_cls : + Class of error to raise. + + Examples + -------- + >>> _api.getitem_checked({"foo": "bar"}, arg=arg) + """ + if len(kwargs) != 1: + raise ValueError("getitem_checked takes a single keyword argument") + (k, v), = kwargs.items() + try: + return mapping[v] + except KeyError: + raise _error_cls(list_suggestion_error_msg(k, v, mapping.keys())) 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_to_prop`` attribute under the format + ``{"alias": "property", ...}` on the class, and can be used by + `.normalize_kwargs`. + """ + 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}") + + alias_to_prop = { + alias: prop for prop, aliases in alias_d.items() for alias in aliases} + + def get_aliased_and_aliases(d): + return {*d.keys(), *d.values()} + + preexisting_aliases = getattr(cls, "_alias_to_prop", {}) + conflicting = (get_aliased_and_aliases(preexisting_aliases) + & get_aliased_and_aliases(alias_to_prop)) + if conflicting: + # Need to decide on conflict resolution policy. + raise NotImplementedError( + f"Parent class already defines conflicting aliases: {conflicting}") + cls._alias_to_prop = {**preexisting_aliases, **alias_to_prop} + 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..58dee136e233 --- /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 import Self + +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: ... +UNSET = _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 list_suggestion_error_msg(name: str, potential: Any, values: Sequence[Any]) -> str: ... +def check_in_list(values: Sequence[Any], /, **kwargs: Any) -> None: ... +def check_shape(shape: tuple[int | None, ...], /, **kwargs: NDArray) -> None: ... +def getitem_checked(mapping: Mapping[Any, _T], /, _error_cls: type[Exception] = ..., **kwargs: Any) -> _T: ... +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..10fa3e31fd5d --- /dev/null +++ b/lib/matplotlib/_api/deprecation.py @@ -0,0 +1,533 @@ +""" +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): + __tracebackhide__ = True + 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): + __tracebackhide__ = True + + 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): + __tracebackhide__ = True + + 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. + + Examples + -------- + Assume we want to only allow *dataset* and *positions* as positional + parameters on the method :: + + def violinplot(self, dataset, positions=None, vert=None, ...) + + Introduce the deprecation by adding the decorator :: + + @_api.make_keyword_only("3.10", "vert") + def violinplot(self, dataset, positions=None, vert=None, ...) + + When the deprecation expires, switch to :: + + def violinplot(self, dataset, positions=None, *, vert=None, ...) + + """ + + 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): + __tracebackhide__ = True + + # 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..cdad80bc9ddc 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,518 @@ 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 ), + ) + +# Okabe-Ito accessible and print-friendly color palette. +# By Masataka Okabe (Jikei Medical School) and Kei Ito (University of Tokyo). +# Qualitative color palette that is unambiguous regardless of whether +# the viewer has colorblindness. https://jfly.uni-koeln.de/color/#pallet + +_okabe_ito_data = ( + (0.0, 0.0, 0.0), # black + (0.9019607843137255, 0.6235294117647059, 0.0), # e69f00 + (0.33725490196078434, 0.7058823529411765, 0.9137254901960784), # 56b4e9 + (0.0, 0.6196078431372549, 0.45098039215686275), # 009e73 + (0.9411764705882353, 0.8941176470588236, 0.25882352941176473), # f0e442 + (0.0, 0.4470588235294118, 0.6980392156862745), # 0072b2 + (0.8352941176470589, 0.3686274509803922, 0.0), # d55e00 + (0.8, 0.4745098039215686, 0.6549019607843137), # cc79a7 +) + +_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 +980,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 +1036,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 +1120,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 +1234,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 +1266,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 +1293,207 @@ 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}, + 'okabe_ito': {'listed': _okabe_ito_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..688e243accda --- /dev/null +++ b/lib/matplotlib/_cm_bivar.py @@ -0,0 +1,1288 @@ +import numpy as np +from matplotlib.colors import SegmentedBivarColormap + +# auto-generated by https://github.com/trygvrad/multivariate_colormaps +# date: 2024-05-24 +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.0, 0.0, 0.0, 0.0, 0.5, 1.0, + 1.0, 0.5, 0.0, 1.0, 1.0, 1.0, + ]).reshape((2, 2, 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..ce488d555898 --- /dev/null +++ b/lib/matplotlib/_constrained_layout.py @@ -0,0 +1,824 @@ +""" +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, + compress=True) + 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: + leftcb = lg1.margin_vals['leftcb'][ss1.colspan[1:]] + rightcb = lg1.margin_vals['rightcb'][ss1.colspan[:-1]] + maxsubl = np.max(lg1.margin_vals['left'][ss1.colspan[1:]] + leftcb) + maxsubr = np.max(lg1.margin_vals['right'][ss1.colspan[:-1]] + rightcb) + 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, cb in zip(ss1.colspan[1:], leftcb): + lg1.edit_margin_min('left', maxsubl - cb, cell=i) + for i, cb in zip(ss1.colspan[:-1], rightcb): + lg1.edit_margin_min('right', maxsubr - cb, cell=i) + + # interior rows: + if len(ss1.rowspan) > 1: + topcb = lg1.margin_vals['topcb'][ss1.rowspan[1:]] + bottomcb = lg1.margin_vals['bottomcb'][ss1.rowspan[:-1]] + maxsubt = np.max(lg1.margin_vals['top'][ss1.rowspan[1:]] + topcb) + maxsubb = np.max(lg1.margin_vals['bottom'][ss1.rowspan[:-1]] + bottomcb) + 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, cb in zip(ss1.rowspan[1:], topcb): + lg1.edit_margin_min('top', maxsubt - cb, cell=i) + for i, cb in zip(ss1.rowspan[:-1], bottomcb): + lg1.edit_margin_min('bottom', maxsubb - cb, 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, compress=False): + """ + 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, compress=compress) + + 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, compress=compress) + + +def reposition_colorbar(layoutgrids, cbax, renderer, *, offset=None, compress=False): + """ + 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. + compress : bool + Whether we're in compressed layout mode. + """ + + 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'] + + # For colorbars with a single parent in compressed layout, + # use the actual visual size of the parent axis after apply_aspect() + # has been called. This ensures colorbars align with their parent axes. + # This fix is specific to single-parent colorbars where alignment is critical. + if compress and len(parents) == 1: + from matplotlib.transforms import Bbox + # Get the actual parent position after apply_aspect() + parent_ax = parents[0] + actual_pos = parent_ax.get_position(original=False) + # Transform to figure coordinates + actual_pos_fig = actual_pos.transformed(fig.transSubfigure - fig.transFigure) + + if location in ('left', 'right'): + # For vertical colorbars, use the actual parent bbox height + # for colorbar sizing + # Keep the pb x-coordinates but use actual y-coordinates + pb = Bbox.from_extents(pb.x0, actual_pos_fig.y0, + pb.x1, actual_pos_fig.y1) + elif location in ('top', 'bottom'): + # For horizontal colorbars, use the actual parent bbox width + # for colorbar sizing + # Keep the pb y-coordinates but use actual x-coordinates + pb = Bbox.from_extents(actual_pos_fig.x0, pb.y0, + actual_pos_fig.x1, pb.y1) + + 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..7bb256a3032b --- /dev/null +++ b/lib/matplotlib/_docstring.pyi @@ -0,0 +1,33 @@ +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: ... + + +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..d85c5c5f03db --- /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..17dc1b8fb462 --- /dev/null +++ b/lib/matplotlib/_mathtext.py @@ -0,0 +1,3054 @@ +""" +Implementation details for :mod:`.mathtext`. +""" + +from __future__ import annotations + +import abc +import copy +import enum +import functools +import itertools +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, 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 CharacterCodeType, Glyph, GlyphIndexType + + +ParserElement.enable_packrat() +_log = logging.getLogger("matplotlib.mathtext") + + +############################################################################## +# FONTS + + +def get_unicode_index(symbol: str) -> CharacterCodeType: # 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, CharacterCodeType, GlyphIndexType, 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]] = [] # (x, y, w, h) + + 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, info.glyph_index, + ox, h - oy + info.offset) + for ox, oy, info in self.glyphs] + rs = [(bx, h - (by + bh), bw, bh) + for bx, by, bw, bh in self.rects] + # Output.rects has downwards ys, VectorParse.rects has upwards ys. + 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], + *[x for x, y, w, h in self.rects], 0]) - 1 + ymin = min([*[oy - info.metrics.ymax for ox, oy, info in self.glyphs], + *[y for x, y, w, h in self.rects], 0]) - 1 + xmax = max([*[ox + info.metrics.xmax for ox, oy, info in self.glyphs], + *[x + w for x, y, w, h in self.rects], 0]) + 1 + ymax = max([*[oy - info.metrics.ymin for ox, oy, info in self.glyphs], + *[y + h for x, y, w, h 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 x, y, bw, bh in shifted.rects: + height = max(int(bh) - 1, 0) + if height == 0: + center = y + bh / 2 + y = int(center - (height + 1) / 2) + else: + y = int(y) + x1 = math.floor(x) + x2 = math.ceil(x + bw) + 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: CharacterCodeType + glyph_index: GlyphIndexType + 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", "normal", "bb", "frak", "scr". "default" + and "regular" are synonyms and use the non-math font. + "normal" denotes the normal 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, + x: float, y: float, w: float, h: float) -> None: + """ + Draw a filled rectangle at (*x*, *y*) with size (*w*, *h*). + """ + output.rects.append((x, y, w, h)) + + def get_axis_height(self, font: str, fontsize: float, dpi: float) -> float: + """ + Get the axis height for the given *font* and *fontsize*. + """ + raise NotImplementedError() + + def get_quad(self, font: str, fontsize: float, dpi: float) -> float: + """ + Get the size of a quad for the given *font* and *fontsize*. + """ + raise NotImplementedError() + + 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)] + + def get_font_constants(self) -> type[FontConstantsBase]: + return FontConstantsBase + + +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, 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) -> FT2Font: + basename = self.fontmap.get(font, 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, CharacterCodeType, 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_index = font.get_char_index(num) + glyph = font.load_glyph(glyph_index, 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_index=glyph_index, + glyph=glyph, + offset=offset + ) + + def get_axis_height(self, fontname: str, fontsize: float, dpi: float) -> float: + consts = self.get_font_constants() + if consts.axis_height is not None: + return consts.axis_height * fontsize * dpi / 72 + else: + # The fraction line (if present) must be aligned with the minus sign. + # Therefore, the height of the latter from the baseline is the axis height. + metrics = self.get_metrics( + fontname, mpl.rcParams['mathtext.default'], '\u2212', fontsize, dpi) + return (metrics.ymax + metrics.ymin) / 2 + + def get_quad(self, fontname: str, fontsize: float, dpi: float) -> float: + consts = self.get_font_constants() + if consts.quad is not None: + return consts.quad * fontsize * dpi / 72 + else: + # With no other option, we measure the size of an 'm'. + metrics = self.get_metrics( + fontname, mpl.rcParams['mathtext.default'], 'm', fontsize, dpi) + return metrics.advance + + def get_xheight(self, fontname: str, fontsize: float, dpi: float) -> float: + consts = self.get_font_constants() + if consts.x_height is not None: + return consts.x_height * fontsize * dpi / 72 + else: + # Some fonts report the wrong x-height, while some don't store it, so + # we do a poor man's x-height. + metrics = self.get_metrics( + fontname, mpl.rcParams['mathtext.default'], 'x', fontsize, dpi) + return metrics.iceberg + + 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) * fontsize * dpi) / 72 + + 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.glyph_index, info2.glyph_index, + 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 = { + 'normal': 'cmmi10', + 'cal': 'cmsy10', + 'rm': 'cmr10', + 'tt': 'cmtt10', + 'it': 'cmti10', + '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, CharacterCodeType, bool]: + font = None + + if fontname in self.fontmap and sym in latex_to_bakoma: + basename, num = latex_to_bakoma[sym] + slanted = (basename in ("cmmi10", "cmti10")) or sym in self._slanted_symbols + font = self._get_font(basename) + elif len(sym) == 1: + slanted = (fontname in ("it", "normal")) + if fontname == "normal" and sym.isdigit(): + # use digits from cmr (roman alphabet) instead of cmm (math alphabet), + # same as LaTeX does. + fontname = "rm" + slanted = False + 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 + # Auto(Height|Width)Char classes will use these alternatives and select the best + # (closest sized) glyph. + _latex_sizes = ('big', 'Big', 'bigg', 'Bigg') + _size_alternatives = { + '(': [('rm', '('), *[('ex', fr'\__parenleft{s}__') for s in _latex_sizes]], + ')': [('rm', ')'), *[('ex', fr'\__parenright{s}__') for s in _latex_sizes]], + '{': [('ex', fr'\__braceleft{s}__') for s in _latex_sizes], + '}': [('ex', fr'\__braceright{s}__') for s in _latex_sizes], + '[': [('rm', '['), *[('ex', fr'\__bracketleft{s}__') for s in _latex_sizes]], + ']': [('rm', ']'), *[('ex', fr'\__bracketright{s}__') for s in _latex_sizes]], + '<': [('cal', r'\__angbracketleft__'), + *[('ex', fr'\__angbracketleft{s}__') for s in _latex_sizes]], + '>': [('cal', r'\__angbracketright__'), + *[('ex', fr'\__angbracketright{s}__') for s in _latex_sizes]], + r'\lfloor': [('ex', fr'\__floorleft{s}__') for s in _latex_sizes], + r'\rfloor': [('ex', fr'\__floorright{s}__') for s in _latex_sizes], + r'\lceil': [('ex', fr'\__ceilingleft{s}__') for s in _latex_sizes], + r'\rceil': [('ex', fr'\__ceilingright{s}__') for s in _latex_sizes], + r'\__sqrt__': [('ex', fr'\__radical{s}__') for s in _latex_sizes], + r'\backslash': [('ex', fr'\__backslash{s}__') for s in _latex_sizes], + r'/': [('rm', '/'), *[('ex', fr'\__slash{s}__') for s in _latex_sizes]], + r'\widehat': [('rm', '\x5e'), ('ex', r'\__hatwide__'), ('ex', r'\__hatwider__'), + ('ex', r'\__hatwidest__')], + r'\widetilde': [('rm', '\x7e'), ('ex', r'\__tildewide__'), + ('ex', r'\__tildewider__'), ('ex', r'\__tildewidest__')], + } + + for alias, target in [(r'\leftparen', '('), (r'\rightparen', ')'), + (r'\leftbrace', '{'), (r'\rightbrace', '}'), + (r'\leftbracket', '['), (r'\rightbracket', ']'), + (r'\langle', '<'), (r'\rangle', '>'), + (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)]) + + def get_font_constants(self) -> type[FontConstantsBase]: + return ComputerModernFontConstants + + +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: dict[CharacterCodeType, CharacterCodeType] = { + 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] # type: ignore[index] + 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: CharacterCodeType) -> tuple[str, CharacterCodeType]: + return fontname, uniindex + + def _get_glyph(self, fontname: str, font_class: str, + sym: str) -> tuple[FT2Font, CharacterCodeType, 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 == 'normal' and uniindex < 0x10000: + # normal mathematics font + char = chr(uniindex) + if (unicodedata.category(char)[0] != "L" + or unicodedata.name(char).startswith("GREEK CAPITAL")): + new_fontname = 'rm' + else: + new_fontname = 'it' + + 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', 'normal') + 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 BakomaFonts._fontmap.values(): + family = "Computer Modern" + _log.info("Substituting symbol %s from %s", sym, family) + return g + + else: + if (fontname in ('it', 'regular', 'normal') + 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, 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, CharacterCodeType, 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', + } + + def get_font_constants(self) -> type[FontConstantsBase]: + return DejaVuSerifFontConstants + + +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', + } + + def get_font_constants(self) -> type[FontConstantsBase]: + return DejaVuSansFontConstants + + +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', + '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: CharacterCodeType) -> tuple[str, CharacterCodeType]: + # 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', 'normal'): + 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(self, fontname: str, + sym: str) -> list[tuple[str, 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 = [(str(i), chr(uniindex)) for i in range(6) + if self._get_font(str(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 + + def get_font_constants(self) -> type[FontConstantsBase]: + if self._sans: + return STIXSansFontConstants + else: + return STIXFontConstants + + +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 superscripts drop below the top of large box + supdrop: T.ClassVar[float] = 0.4 + + # Percentage of x-height that subscripts drop below the bottom of large box + 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 + + # Percentage of x-height the numerator is shifted up in display style. + num1: T.ClassVar[float] = 1.4 + + # Percentage of x-height the numerator is shifted up in text, script and + # scriptscript styles if there is a fraction line. + num2: T.ClassVar[float] = 1.5 + + # Percentage of x-height the numerator is shifted up in text, script and + # scriptscript styles if there is no fraction line. + num3: T.ClassVar[float] = 1.3 + + # Percentage of x-height the denominator is shifted down in display style. + denom1: T.ClassVar[float] = 1.3 + + # Percentage of x-height the denominator is shifted down in text, script + # and scriptscript styles. + denom2: T.ClassVar[float] = 1.1 + + # The height of a horizontal reference line used for positioning elements in a + # formula, similar to a baseline, as a multiple of design size. + axis_height: T.ClassVar[float | None] = None + + # The size of a quad space in LaTeX, as a multiple of design size. + quad: T.ClassVar[float | None] = None + + # The size of x-height in font design units (i.e., divided by units-per-em). If not + # provided, then this will be measured from the font itself. + x_height: T.ClassVar[float | None] = None + + +class ComputerModernFontConstants(FontConstantsBase): + # Previously, the x-height of Computer Modern was obtained from the font + # table. However, that x-height was greater than the the actual (rendered) + # x-height by a factor of 1.771484375 (at font size 12, DPI 100 and hinting + # type 32). Now that we're using the rendered x-height, some font constants + # have been increased by the same factor to compensate. + script_space = 0.132861328125 + delta = 0.132861328125 + delta_slanted = 0.3 + delta_integral = 0.3 + _x_height = 451470 + # These all come from the cmsy10.tfm metrics, divided by the design xheight from + # there, since we multiply these values by the scaled xheight later. + supdrop = 404864 / _x_height + subdrop = 52429 / _x_height + sup1 = 432949 / _x_height + sub1 = 157286 / _x_height + sub2 = 259226 / _x_height + num1 = 709370 / _x_height + num2 = 412858 / _x_height + num3 = 465286 / _x_height + denom1 = 719272 / _x_height + denom2 = 361592 / _x_height + # These come from the cmsy10.tfm metrics, scaled so they are in multiples of design + # size. + axis_height = 262144 / 2**20 + quad = 1048579 / 2**20 + x_height = _x_height / 2**20 + + +class STIXFontConstants(FontConstantsBase): + script_space = 0.1 + delta = 0.05 + delta_slanted = 0.3 + delta_integral = 0.3 + _x_height = 450 + x_height = _x_height / 1000 + # These values are extracted from the TeX table of STIXGeneral.ttf using FontForge, + # and then divided by design xheight, since we multiply these values by the scaled + # xheight later. + supdrop = 386 / _x_height + subdrop = 50.0002 / _x_height + sup1 = 413 / _x_height + sub1 = 150 / _x_height + sub2 = 309 / _x_height + num1 = 747 / _x_height + num2 = 424 / _x_height + num3 = 474 / _x_height + denom1 = 756 / _x_height + denom2 = 375 / _x_height + # These come from the same TeX table, scaled by Em size so they are in multiples of + # design size. + axis_height = 250 / 1000 + quad = 1000 / 1000 + + +class STIXSansFontConstants(STIXFontConstants): + script_space = 0.05 + delta_slanted = 0.6 + delta_integral = 0.3 + + +class DejaVuSerifFontConstants(FontConstantsBase): + _x_height = 1063 + x_height = _x_height / 2048 + # These values are extracted from the TeX table of DejaVuSerif.ttf using FontForge, + # and then divided by design xheight, since we multiply these values by the scaled + # xheight later. + supdrop = 790.527 / _x_height + subdrop = 102.4 / _x_height + sup1 = 845.824 / _x_height + sub1 = 307.199 / _x_height + sub2 = 632.832 / _x_height + num1 = 1529.86 / _x_height + num2 = 868.352 / _x_height + num3 = 970.752 / _x_height + denom1 = 1548.29 / _x_height + denom2 = 768 / _x_height + # These come from the same TeX table, scaled by Em size so they are in multiples of + # design size. + axis_height = 512 / 2048 + + +class DejaVuSansFontConstants(FontConstantsBase): + _x_height = 1120 + x_height = _x_height / 2048 + # These values are extracted from the TeX table of DejaVuSans.ttf using FontForge, + # and then divided by design xheight, since we multiply these values by the scaled + # xheight later. + supdrop = 790.527 / _x_height + subdrop = 102.4 / _x_height + sup1 = 845.824 / _x_height + sub1 = 307.199 / _x_height + sub2 = 632.832 / _x_height + num1 = 1529.86 / _x_height + num2 = 868.352 / _x_height + num3 = 970.752 / _x_height + denom1 = 1548.29 / _x_height + denom2 = 768 / _x_height + # These come from the same TeX table, scaled by Em size so they are in multiples of + # design size. + axis_height = 512 / 2048 + + +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.""" + + def is_char_node(self) -> bool: + # TeX defines a `char_node` as one which represents a single character, + # but also states that a `char_node` will never appear in a `Vlist` + # (node134). Further, nuclei made of one `Char` and nuclei made of + # multiple `Char`s have their superscripts and subscripts shifted by + # the same amount. In order to make Mathtext behave similarly, just + # check whether this node is a `Vlist` or has any `Vlist` descendants. + return True + + +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) -> str: + 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) + self.is_phantom = False + + def is_char_node(self) -> bool: + # See description in Node.is_char_node. + return all(map(lambda node: node.is_char_node(), self.children)) + + 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 = [] + for elem0, elem1 in itertools.zip_longest(self.children, self.children[1:]): + new_children.append(elem0) + kerning_distance = elem0.get_kerning(elem1) + 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 is_char_node(self) -> bool: + # See description in Node.is_char_node. + return False + + 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 - h, w, 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, + factor: float | None = None): + alternatives = state.fontset.get_sized_alternatives_for_symbol(state.font, c) + + x_height = 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 * x_height + if char.height + char.depth >= target_total - 0.2 * x_height: + 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, + 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) + phantom: list[bool] = [] + + def render(node, *args): + if not any(phantom): + node.render(*args) + + 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 + + phantom.append(box.is_phantom) + + for p in box.children: + if isinstance(p, Char): + render(p, 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 + render(p, 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 + + phantom.pop() + + 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 + render(p, 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 ('normal', '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 normal".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.phantom = cmd(r"\phantom", p.optional_group("value")) + p.llap = cmd(r"\llap", p.optional_group("value")) + p.rlap = cmd(r"\rlap", p.optional_group("value")) + + 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.underline = cmd(r"\underline", 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.phantom | p.llap | p.rlap + | 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.underline + | p.text + | p.boldsymbol + | p.substack + | p.auto_delim + ) + + 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._needs_space_after_subsuper = 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: + raise ValueError("\n" + err.explain(0)) from None + self._state_stack = [] + self._needs_space_after_subsuper = 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 'normal' + 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 normal style so that horizontal spaces don't depend on the + # current font style. + # TODO: this should be read from the font file + state = self.get_state() + key = (state.font, state.fontsize, state.dpi) + width = self._em_width_cache.get(key) + if width is None: + width = state.fontset.get_quad('normal', state.fontsize, state.dpi) + 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._needs_space_after_subsuper 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']}") + + def phantom(self, toks: ParseResults) -> T.Any: + toks["value"].is_phantom = True + return toks["value"] + + def llap(self, toks: ParseResults) -> T.Any: + return [Hlist([Kern(-toks["value"].width), toks["value"]])] + + def rlap(self, toks: ParseResults) -> T.Any: + return [Hlist([toks["value"], Kern(-toks["value"].width)])] + + _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) + centered = HCentered([accent_box]) + 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: + # 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 sub/superscript, set flag to true to tell subsuper + # to add space after this operator. + self._needs_space_after_subsuper = next_char in {'^', '_'} + 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) + x_height = 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 + optional_spacing = ([self._make_space(self._space_widths[r'\,'])] + if self._needs_space_after_subsuper else []) + self._needs_space_after_subsuper = False + result = Hlist([vlt, *optional_spacing]) + 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 + consts = state.fontset.get_font_constants() + lc_height = last_char.height + lc_baseline = 0.0 + if self.is_dropsub(last_char): + lc_baseline = last_char.depth + + # Compute kerning for sub and super + superkern = consts.delta * x_height + subkern = consts.delta * x_height + if self.is_slanted(last_char): + superkern += consts.delta * x_height + superkern += consts.delta_slanted * (lc_height - x_height * 2 / 3) + if self.is_dropsub(last_char): + subkern = (3 * consts.delta - consts.delta_integral) * lc_height + superkern = (3 * consts.delta + consts.delta_integral) * lc_height + else: + subkern = 0 + + # Set the minimum shifts for the superscript and subscript (node756). + if nucleus.is_char_node(): + shift_up = 0.0 + shift_down = 0.0 + else: + shrunk_x_height = state.fontset.get_xheight( + state.font, state.fontsize * SHRINK_FACTOR, state.dpi) + shift_up = nucleus.height - consts.supdrop * shrunk_x_height + shift_down = nucleus.depth + consts.subdrop * shrunk_x_height + + x: List + if super is None: + # Align subscript without superscript (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 + consts.subdrop * x_height + else: + shift_down = max(shift_down, consts.sub1 * x_height, + x.height - x_height * 4 / 5) + x.shift_amount = shift_down + else: + # Align superscript (node758). + x = Hlist([Kern(superkern), super]) + x.shrink() + if self.is_dropsub(last_char): + shift_up = lc_height - consts.subdrop * x_height + else: + shift_up = max(shift_up, consts.sup1 * x_height, x.depth + x_height / 4) + if sub is None: + x.shift_amount = -shift_up + else: + # Align subscript with superscript (node759). + y = Hlist([Kern(subkern), sub]) + y.shrink() + if self.is_dropsub(last_char): + shift_down = lc_baseline + consts.subdrop * x_height + else: + shift_down = max(shift_down, consts.sub2 * x_height) + # If the subscript and superscript are too close to each other, + # move the subscript down. + clr = (4 * rule_thickness - + ((shift_up - x.depth) - (y.height - shift_down))) + if clr > 0.: + shift_down += clr + clr = x_height * 4 / 5 - shift_up + x.depth + if clr > 0: + shift_up += clr + shift_down -= 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 += consts.script_space * x_height + + # Do we need to add a space after the nucleus? + # To find out, check the flag set by operatorname + optional_spacing = ([self._make_space(self._space_widths[r'\,'])] + if self._needs_space_after_subsuper else []) + self._needs_space_after_subsuper = False + result = Hlist([nucleus, x, *optional_spacing]) + 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() + + axis_height = state.fontset.get_axis_height( + state.font, state.fontsize, state.dpi) + consts = state.fontset.get_font_constants() + x_height = state.fontset.get_xheight(state.font, state.fontsize, state.dpi) + + for _ in range(style.value): + x_height *= SHRINK_FACTOR + num.shrink() + den.shrink() + cnum = HCentered([num]) + cden = HCentered([den]) + width = max(num.width, den.width) + cnum.hpack(width, 'exactly') + cden.hpack(width, 'exactly') + + # Align the fraction with a fraction line (node743, node744 and node746). + if rule: + if style is self._MathStyle.DISPLAYSTYLE: + num_shift_up = consts.num1 * x_height + den_shift_down = consts.denom1 * x_height + clr = 3 * rule # The minimum clearance. + else: + num_shift_up = consts.num2 * x_height + den_shift_down = consts.denom2 * x_height + clr = rule # The minimum clearance. + delta = rule / 2 + num_clr = max((num_shift_up - cnum.depth) - (axis_height + delta), clr) + den_clr = max((axis_height - delta) - (cden.height - den_shift_down), clr) + vlist = Vlist([cnum, # numerator + Vbox(0, num_clr), # space + Hrule(state, rule), # rule + Vbox(0, den_clr), # space + cden # denominator + ]) + vlist.shift_amount = cden.height + den_clr + delta - axis_height + + # Align the fraction without a fraction line (node743, node744 and node745). + else: + if style is self._MathStyle.DISPLAYSTYLE: + num_shift_up = consts.num1 * x_height + den_shift_down = consts.denom1 * x_height + min_clr = 7 * thickness # The minimum clearance. + else: + num_shift_up = consts.num3 * x_height + den_shift_down = consts.denom2 * x_height + min_clr = 3 * thickness # The minimum clearance. + def_clr = (num_shift_up - cnum.depth) - (cden.height - den_shift_down) + clr = max(def_clr, min_clr) + vlist = Vlist([cnum, # numerator + Vbox(0, clr), # space + cden # denominator + ]) + vlist.shift_amount = den_shift_down + if def_clr < min_clr: + vlist.shift_amount += (min_clr - def_clr) / 2 + + result: list[Box | Char | str] = [Hlist([ + Hbox(thickness), + vlist, + Hbox(thickness) + ])] + if ldelim or rdelim: + return self._auto_sized_delimiter(ldelim or ".", result, rdelim or ".") + 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 + 5 * thickness + depth = body.depth + body.shift_amount + check = AutoHeightChar(r'\__sqrt__', height, depth, state) + 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 * 12), + '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(0.5 * check.width, 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 + Kern(-0.5 * check.width), # Negative kerning to put root over tick + 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 + 3 * thickness + 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 * 12), + 'exactly', depth) + + hlist = Hlist([rightside]) + return [hlist] + + def underline(self, toks: ParseResults) -> T.Any: + body = toks["body"] + state = self.get_state() + thickness = state.get_current_underline_thickness() + # Place the underline below `body` (node735). + vlist = Vlist([ + Hlist([body]), + Kern(3 * thickness), + Hrule(state, thickness), + ]) + delta = vlist.height + vlist.depth + thickness + vlist.height = body.height + vlist.depth = delta - vlist.height + return [Hlist([vlist])] + + 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"], toks["mid"].as_list(), 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..6d0c20a1b2a2 100644 --- a/lib/matplotlib/_mathtext_data.py +++ b/lib/matplotlib/_mathtext_data.py @@ -1,2567 +1,1810 @@ """ 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 __future__ import annotations +from typing import TypeAlias, overload -""" -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 .ft2font import CharacterCodeType -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), +latex_to_bakoma: dict[str, tuple[str, CharacterCodeType]] = { + '\\__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), - r'\prime' : ('cmsy10', 73), + '\\__angbracketleft__' : ('cmsy10', 0x68), + '\\__angbracketright__' : ('cmsy10', 0x69), + '\\__angbracketleftbig__' : ('cmex10', 0xad), + '\\__angbracketleftBig__' : ('cmex10', 0x44), + '\\__angbracketleftbigg__' : ('cmex10', 0xbf), + '\\__angbracketleftBigg__' : ('cmex10', 0x2a), + '\\__angbracketrightbig__' : ('cmex10', 0xae), + '\\__angbracketrightBig__' : ('cmex10', 0x45), + '\\__angbracketrightbigg__' : ('cmex10', 0xc0), + '\\__angbracketrightBigg__' : ('cmex10', 0x2b), + '\\__backslashbig__' : ('cmex10', 0xb2), + '\\__backslashBig__' : ('cmex10', 0x2f), + '\\__backslashbigg__' : ('cmex10', 0xc2), + '\\__backslashBigg__' : ('cmex10', 0x2d), + '\\__braceleftbig__' : ('cmex10', 0xa9), + '\\__braceleftBig__' : ('cmex10', 0x6e), + '\\__braceleftbigg__' : ('cmex10', 0xbd), + '\\__braceleftBigg__' : ('cmex10', 0x28), + '\\__bracerightbig__' : ('cmex10', 0xaa), + '\\__bracerightBig__' : ('cmex10', 0x6f), + '\\__bracerightbigg__' : ('cmex10', 0xbe), + '\\__bracerightBigg__' : ('cmex10', 0x29), + '\\__bracketleftbig__' : ('cmex10', 0xa3), + '\\__bracketleftBig__' : ('cmex10', 0x68), + '\\__bracketleftbigg__' : ('cmex10', 0x2219), + '\\__bracketleftBigg__' : ('cmex10', 0x22), + '\\__bracketrightbig__' : ('cmex10', 0xa4), + '\\__bracketrightBig__' : ('cmex10', 0x69), + '\\__bracketrightbigg__' : ('cmex10', 0xb8), + '\\__bracketrightBigg__' : ('cmex10', 0x23), + '\\__ceilingleftbig__' : ('cmex10', 0xa7), + '\\__ceilingleftBig__' : ('cmex10', 0x6c), + '\\__ceilingleftbigg__' : ('cmex10', 0xbb), + '\\__ceilingleftBigg__' : ('cmex10', 0x26), + '\\__ceilingrightbig__' : ('cmex10', 0xa8), + '\\__ceilingrightBig__' : ('cmex10', 0x6d), + '\\__ceilingrightbigg__' : ('cmex10', 0xbc), + '\\__ceilingrightBigg__' : ('cmex10', 0x27), + '\\__floorleftbig__' : ('cmex10', 0xa5), + '\\__floorleftBig__' : ('cmex10', 0x6a), + '\\__floorleftbigg__' : ('cmex10', 0xb9), + '\\__floorleftBigg__' : ('cmex10', 0x24), + '\\__floorrightbig__' : ('cmex10', 0xa6), + '\\__floorrightBig__' : ('cmex10', 0x6b), + '\\__floorrightbigg__' : ('cmex10', 0xba), + '\\__floorrightBigg__' : ('cmex10', 0x25), + '\\__hatwide__' : ('cmex10', 0x62), + '\\__hatwider__' : ('cmex10', 0x63), + '\\__hatwidest__' : ('cmex10', 0x64), + '\\__parenleftbig__' : ('cmex10', 0xa1), + '\\__parenleftBig__' : ('cmex10', 0xb3), + '\\__parenleftbigg__' : ('cmex10', 0xb5), + '\\__parenleftBigg__' : ('cmex10', 0xc3), + '\\__parenrightbig__' : ('cmex10', 0xa2), + '\\__parenrightBig__' : ('cmex10', 0xb4), + '\\__parenrightbigg__' : ('cmex10', 0xb6), + '\\__parenrightBigg__' : ('cmex10', 0x21), + '\\__radicalbig__' : ('cmex10', 0x70), + '\\__radicalBig__' : ('cmex10', 0x71), + '\\__radicalbigg__' : ('cmex10', 0x72), + '\\__radicalBigg__' : ('cmex10', 0x73), + '\\__slashbig__' : ('cmex10', 0xb1), + '\\__slashBig__' : ('cmex10', 0x2e), + '\\__slashbigg__' : ('cmex10', 0xc1), + '\\__slashBigg__' : ('cmex10', 0x2c), + '\\__tildewide__' : ('cmex10', 0x65), + '\\__tildewider__' : ('cmex10', 0x66), + '\\__tildewidest__' : ('cmex10', 0x67), - # 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), + ':' : ('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, +type12uni: dict[str, CharacterCodeType] = { '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()} -tex2uni = { - 'widehat' : 0x0302, - 'widetilde' : 0x0303, - 'widebar' : 0x0305, - 'langle' : 0x27e8, - 'rangle' : 0x27e9, - 'perp' : 0x27c2, - 'neq' : 0x2260, - 'Join' : 0x2a1d, - 'leqslant' : 0x2a7d, - 'geqslant' : 0x2a7e, - 'lessapprox' : 0x2a85, - 'gtrapprox' : 0x2a86, - 'lesseqqgtr' : 0x2a8b, - 'gtreqqless' : 0x2a8c, - 'triangleeq' : 0x225c, - 'eqslantless' : 0x2a95, - 'eqslantgtr' : 0x2a96, - 'backepsilon' : 0x03f6, - 'precapprox' : 0x2ab7, - 'succapprox' : 0x2ab8, - 'fallingdotseq' : 0x2252, - 'subseteqq' : 0x2ac5, - 'supseteqq' : 0x2ac6, - 'varpropto' : 0x221d, - 'precnapprox' : 0x2ab9, - 'succnapprox' : 0x2aba, - 'subsetneqq' : 0x2acb, - 'supsetneqq' : 0x2acc, - 'lnapprox' : 0x2ab9, - 'gnapprox' : 0x2aba, - 'longleftarrow' : 0x27f5, - 'longrightarrow' : 0x27f6, - 'longleftrightarrow' : 0x27f7, - 'Longleftarrow' : 0x27f8, - 'Longrightarrow' : 0x27f9, - 'Longleftrightarrow' : 0x27fa, - 'longmapsto' : 0x27fc, - 'leadsto' : 0x21dd, - 'dashleftarrow' : 0x290e, - 'dashrightarrow' : 0x290f, - 'circlearrowleft' : 0x21ba, - 'circlearrowright' : 0x21bb, - 'leftrightsquigarrow' : 0x21ad, - 'leftsquigarrow' : 0x219c, - 'rightsquigarrow' : 0x219d, - 'Game' : 0x2141, - 'hbar' : 0x0127, - 'hslash' : 0x210f, - 'ldots' : 0x2026, - 'vdots' : 0x22ee, - 'doteqdot' : 0x2251, - 'doteq' : 8784, - 'partial' : 8706, - 'gg' : 8811, - 'asymp' : 8781, - 'blacktriangledown' : 9662, - 'otimes' : 8855, - 'nearrow' : 8599, - 'varpi' : 982, - 'vee' : 8744, - 'vec' : 8407, - 'smile' : 8995, - 'succnsim' : 8937, - 'gimel' : 8503, - 'vert' : 124, - '|' : 124, - 'varrho' : 1009, - 'P' : 182, - 'approxident' : 8779, - 'Swarrow' : 8665, - 'textasciicircum' : 94, - 'imageof' : 8887, - 'ntriangleleft' : 8938, - 'nleq' : 8816, - 'div' : 247, - 'nparallel' : 8742, - 'Leftarrow' : 8656, - 'lll' : 8920, - 'oiint' : 8751, - 'ngeq' : 8817, - 'Theta' : 920, - 'origof' : 8886, - 'blacksquare' : 9632, - 'solbar' : 9023, - 'neg' : 172, - 'sum' : 8721, - 'Vdash' : 8873, - 'coloneq' : 8788, - 'degree' : 176, - 'bowtie' : 8904, - 'blacktriangleright' : 9654, - 'varsigma' : 962, - 'leq' : 8804, - 'ggg' : 8921, - 'lneqq' : 8808, - 'scurel' : 8881, - 'stareq' : 8795, - 'BbbN' : 8469, - 'nLeftarrow' : 8653, - 'nLeftrightarrow' : 8654, - 'k' : 808, - 'bot' : 8869, - 'BbbC' : 8450, - 'Lsh' : 8624, - 'leftleftarrows' : 8647, - 'BbbZ' : 8484, - 'digamma' : 989, - 'BbbR' : 8477, - 'BbbP' : 8473, - 'BbbQ' : 8474, - 'vartriangleright' : 8883, - 'succsim' : 8831, - 'wedge' : 8743, - 'lessgtr' : 8822, - 'veebar' : 8891, - 'mapsdown' : 8615, - 'Rsh' : 8625, - 'chi' : 967, - 'prec' : 8826, - 'nsubseteq' : 8840, - 'therefore' : 8756, - 'eqcirc' : 8790, - 'textexclamdown' : 161, - 'nRightarrow' : 8655, - 'flat' : 9837, - 'notin' : 8713, - 'llcorner' : 8990, - 'varepsilon' : 949, - 'bigtriangleup' : 9651, - 'aleph' : 8501, - 'dotminus' : 8760, - 'upsilon' : 965, - 'Lambda' : 923, - 'cap' : 8745, - 'barleftarrow' : 8676, - 'mu' : 956, - 'boxplus' : 8862, - 'mp' : 8723, - 'circledast' : 8859, - 'tau' : 964, - 'in' : 8712, - 'backslash' : 92, - 'varnothing' : 8709, - 'sharp' : 9839, - 'eqsim' : 8770, - 'gnsim' : 8935, - 'Searrow' : 8664, - 'updownarrows' : 8645, - 'heartsuit' : 9825, - 'trianglelefteq' : 8884, - 'ddag' : 8225, - 'sqsubseteq' : 8849, - 'mapsfrom' : 8612, - 'boxbar' : 9707, - 'sim' : 8764, - 'Nwarrow' : 8662, - 'nequiv' : 8802, - 'succ' : 8827, - 'vdash' : 8866, - 'Leftrightarrow' : 8660, - 'parallel' : 8741, - 'invnot' : 8976, - 'natural' : 9838, - 'ss' : 223, - 'uparrow' : 8593, - 'nsim' : 8769, - 'hookrightarrow' : 8618, - 'Equiv' : 8803, - 'approx' : 8776, - 'Vvdash' : 8874, - 'nsucc' : 8833, - 'leftrightharpoons' : 8651, - 'Re' : 8476, - 'boxminus' : 8863, - 'equiv' : 8801, - 'Lleftarrow' : 8666, - 'thinspace' : 8201, - 'll' : 8810, - 'Cup' : 8915, - 'measeq' : 8798, - 'upharpoonleft' : 8639, - 'lq' : 8216, - 'Upsilon' : 933, - 'subsetneq' : 8842, - 'greater' : 62, - 'supsetneq' : 8843, - 'Cap' : 8914, - 'L' : 321, - 'spadesuit' : 9824, - 'lrcorner' : 8991, - 'not' : 824, - 'bar' : 772, - 'rightharpoonaccent' : 8401, - 'boxdot' : 8865, - 'l' : 322, - 'leftharpoondown' : 8637, - 'bigcup' : 8899, - 'iint' : 8748, - 'bigwedge' : 8896, - 'downharpoonleft' : 8643, - 'textasciitilde' : 126, - 'subset' : 8834, - 'leqq' : 8806, - 'mapsup' : 8613, - 'nvDash' : 8877, - 'looparrowleft' : 8619, - 'nless' : 8814, - 'rightarrowbar' : 8677, - 'Vert' : 8214, - 'downdownarrows' : 8650, - 'uplus' : 8846, - 'simeq' : 8771, - 'napprox' : 8777, - 'ast' : 8727, - 'twoheaduparrow' : 8607, - 'doublebarwedge' : 8966, - 'Sigma' : 931, - 'leftharpoonaccent' : 8400, - 'ntrianglelefteq' : 8940, - 'nexists' : 8708, - 'times' : 215, - 'measuredangle' : 8737, - 'bumpeq' : 8783, - 'carriagereturn' : 8629, - 'adots' : 8944, - 'checkmark' : 10003, - 'lambda' : 955, - 'xi' : 958, - 'rbrace' : 125, - 'rbrack' : 93, - 'Nearrow' : 8663, - 'maltese' : 10016, - 'clubsuit' : 9827, - 'top' : 8868, - 'overarc' : 785, - 'varphi' : 966, - 'Delta' : 916, - 'iota' : 953, - 'nleftarrow' : 8602, - 'candra' : 784, - 'supset' : 8835, - 'triangleleft' : 9665, - 'gtreqless' : 8923, - 'ntrianglerighteq' : 8941, - 'quad' : 8195, - 'Xi' : 926, - 'gtrdot' : 8919, - 'leftthreetimes' : 8907, - 'minus' : 8722, - 'preccurlyeq' : 8828, - 'nleftrightarrow' : 8622, - 'lambdabar' : 411, - 'blacktriangle' : 9652, - 'kernelcontraction' : 8763, - 'Phi' : 934, - 'angle' : 8736, - 'spadesuitopen' : 9828, - 'eqless' : 8924, - 'mid' : 8739, - 'varkappa' : 1008, - 'Ldsh' : 8626, - 'updownarrow' : 8597, - 'beta' : 946, - 'textquotedblleft' : 8220, - 'rho' : 961, - 'alpha' : 945, - 'intercal' : 8890, - 'beth' : 8502, - 'grave' : 768, - 'acwopencirclearrow' : 8634, - 'nmid' : 8740, - 'nsupset' : 8837, - 'sigma' : 963, - 'dot' : 775, - 'Rightarrow' : 8658, - 'turnednot' : 8985, - 'backsimeq' : 8909, - 'leftarrowtail' : 8610, - 'approxeq' : 8778, - 'curlyeqsucc' : 8927, - 'rightarrowtail' : 8611, - 'Psi' : 936, - 'copyright' : 169, - 'yen' : 165, - 'vartriangleleft' : 8882, - 'rasp' : 700, - 'triangleright' : 9655, - 'precsim' : 8830, - 'infty' : 8734, - 'geq' : 8805, - 'updownarrowbar' : 8616, - 'precnsim' : 8936, - 'H' : 779, - 'ulcorner' : 8988, - 'looparrowright' : 8620, - 'ncong' : 8775, - 'downarrow' : 8595, - 'circeq' : 8791, - 'subseteq' : 8838, - 'bigstar' : 9733, - 'prime' : 8242, - 'lceil' : 8968, - 'Rrightarrow' : 8667, - 'oiiint' : 8752, - 'curlywedge' : 8911, - 'vDash' : 8872, - 'lfloor' : 8970, - 'ddots' : 8945, - 'exists' : 8707, - 'underbar' : 817, - 'Pi' : 928, - 'leftrightarrows' : 8646, - 'sphericalangle' : 8738, - 'coprod' : 8720, - 'circledcirc' : 8858, - 'gtrsim' : 8819, - 'gneqq' : 8809, - 'between' : 8812, - 'theta' : 952, - 'complement' : 8705, - 'arceq' : 8792, - 'nVdash' : 8878, - 'S' : 167, - 'wr' : 8768, - 'wp' : 8472, - 'backcong' : 8780, - 'lasp' : 701, - 'c' : 807, - 'nabla' : 8711, - 'dotplus' : 8724, - 'eta' : 951, - 'forall' : 8704, - 'eth' : 240, - 'colon' : 58, - 'sqcup' : 8852, - 'rightrightarrows' : 8649, - 'sqsupset' : 8848, - 'mapsto' : 8614, - 'bigtriangledown' : 9661, - 'sqsupseteq' : 8850, - 'propto' : 8733, - 'pi' : 960, - 'pm' : 177, - 'dots' : 0x2026, - 'nrightarrow' : 8603, - 'textasciiacute' : 180, - 'Doteq' : 8785, - 'breve' : 774, - 'sqcap' : 8851, - 'twoheadrightarrow' : 8608, - 'kappa' : 954, - 'vartriangle' : 9653, - 'diamondsuit' : 9826, - 'pitchfork' : 8916, - 'blacktriangleleft' : 9664, - 'nprec' : 8832, - 'vdots' : 8942, - 'curvearrowright' : 8631, - 'barwedge' : 8892, - 'multimap' : 8888, - 'textquestiondown' : 191, - 'cong' : 8773, - 'rtimes' : 8906, - 'rightzigzagarrow' : 8669, - 'rightarrow' : 8594, - 'leftarrow' : 8592, - '__sqrt__' : 8730, - 'twoheaddownarrow' : 8609, - 'oint' : 8750, - 'bigvee' : 8897, - 'eqdef' : 8797, - 'sterling' : 163, - 'phi' : 981, - 'Updownarrow' : 8661, - 'backprime' : 8245, - 'emdash' : 8212, - 'Gamma' : 915, - 'i' : 305, - 'rceil' : 8969, - 'leftharpoonup' : 8636, - 'Im' : 8465, - 'curvearrowleft' : 8630, - 'wedgeq' : 8793, - 'fallingdotseq' : 8786, - 'curlyeqprec' : 8926, - 'questeq' : 8799, - 'less' : 60, - 'upuparrows' : 8648, - 'tilde' : 771, - 'textasciigrave' : 96, - 'smallsetminus' : 8726, - 'ell' : 8467, - 'cup' : 8746, - 'danger' : 9761, - 'nVDash' : 8879, - 'cdotp' : 183, - 'cdots' : 8943, - 'hat' : 770, - 'eqgtr' : 8925, - 'enspace' : 8194, - 'psi' : 968, - 'frown' : 8994, - 'acute' : 769, - 'downzigzagarrow' : 8623, - 'ntriangleright' : 8939, - 'cupdot' : 8845, - 'circleddash' : 8861, - 'oslash' : 8856, - 'mho' : 8487, - 'd' : 803, - 'sqsubset' : 8847, - 'cdot' : 8901, - 'Omega' : 937, - 'OE' : 338, - 'veeeq' : 8794, - 'Finv' : 8498, - 't' : 865, - 'leftrightarrow' : 8596, - 'swarrow' : 8601, - 'rightthreetimes' : 8908, - 'rightleftharpoons' : 8652, - 'lesssim' : 8818, - 'searrow' : 8600, - 'because' : 8757, - 'gtrless' : 8823, - 'star' : 8902, - 'nsubset' : 8836, - 'zeta' : 950, - 'dddot' : 8411, - 'bigcirc' : 9675, - 'Supset' : 8913, - 'circ' : 8728, - 'slash' : 8725, - 'ocirc' : 778, - 'prod' : 8719, - 'twoheadleftarrow' : 8606, - 'daleth' : 8504, - 'upharpoonright' : 8638, - 'odot' : 8857, - 'Uparrow' : 8657, - 'O' : 216, - 'hookleftarrow' : 8617, - 'trianglerighteq' : 8885, - 'nsime' : 8772, - 'oe' : 339, - 'nwarrow' : 8598, - 'o' : 248, - 'ddddot' : 8412, - 'downharpoonright' : 8642, - 'succcurlyeq' : 8829, - 'gamma' : 947, - 'scrR' : 8475, - 'dag' : 8224, - 'thickspace' : 8197, - 'frakZ' : 8488, - 'lessdot' : 8918, - 'triangledown' : 9663, - 'ltimes' : 8905, - 'scrB' : 8492, - 'endash' : 8211, - 'scrE' : 8496, - 'scrF' : 8497, - 'scrH' : 8459, - 'scrI' : 8464, - 'rightharpoondown' : 8641, - 'scrL' : 8466, - 'scrM' : 8499, - 'frakC' : 8493, - 'nsupseteq' : 8841, - 'circledR' : 174, - 'circledS' : 9416, - 'ngtr' : 8815, - 'bigcap' : 8898, - 'scre' : 8495, - 'Downarrow' : 8659, - 'scrg' : 8458, - 'overleftrightarrow' : 8417, - 'scro' : 8500, - 'lnsim' : 8934, - 'eqcolon' : 8789, - 'curlyvee' : 8910, - 'urcorner' : 8989, - 'lbrace' : 123, - 'Bumpeq' : 8782, - 'delta' : 948, - 'boxtimes' : 8864, - 'overleftarrow' : 8406, - 'prurel' : 8880, - 'clubsuitopen' : 9831, - 'cwopencirclearrow' : 8635, - 'geqq' : 8807, - 'rightleftarrows' : 8644, - 'ac' : 8766, - 'ae' : 230, - 'int' : 8747, - 'rfloor' : 8971, - 'risingdotseq' : 8787, - 'nvdash' : 8876, - 'diamond' : 8900, - 'ddot' : 776, - 'backsim' : 8765, - 'oplus' : 8853, - 'triangleq' : 8796, - 'check' : 780, - 'ni' : 8715, - 'iiint' : 8749, - 'ne' : 8800, - 'lesseqgtr' : 8922, - 'obar' : 9021, - 'supseteq' : 8839, - 'nu' : 957, - 'AA' : 8491, - 'AE' : 198, - 'models' : 8871, - 'ominus' : 8854, - 'dashv' : 8867, - 'omega' : 969, - 'rq' : 8217, - 'Subset' : 8912, - 'rightharpoonup' : 8640, - 'Rdsh' : 8627, - 'bullet' : 8729, - 'divideontimes' : 8903, - 'lbrack' : 91, - 'textquotedblright' : 8221, - 'Colon' : 8759, - '%' : 37, - '$' : 36, - '{' : 123, - '}' : 125, - '_' : 95, - '#' : 35, - 'imath' : 0x131, - 'circumflexaccent' : 770, - 'combiningbreve' : 774, - 'combiningoverline' : 772, - 'combininggraveaccent' : 768, - 'combiningacuteaccent' : 769, - 'combiningdiaeresis' : 776, - 'combiningtilde' : 771, - 'combiningrightarrowabove' : 8407, - 'combiningdotabove' : 775, - 'to' : 8594, - 'succeq' : 8829, - 'emptyset' : 8709, - 'leftparen' : 40, - 'rightparen' : 41, - 'bigoplus' : 10753, - 'leftangle' : 10216, - 'rightangle' : 10217, - 'leftbrace' : 124, - 'rightbrace' : 125, - 'jmath' : 567, - 'bigodot' : 10752, - 'preceq' : 8828, - 'biguplus' : 10756, - 'epsilon' : 949, - 'vartheta' : 977, - 'bigotimes' : 10754, - 'guillemotleft' : 171, - 'ring' : 730, - 'Thorn' : 222, - 'guilsinglright' : 8250, - 'perthousand' : 8240, - 'macron' : 175, - 'cent' : 162, - 'guillemotright' : 187, - 'equal' : 61, - 'asterisk' : 42, - 'guilsinglleft' : 8249, - 'plus' : 43, - 'thorn' : 254, - 'dagger' : 8224 +# 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: dict[CharacterCodeType, CharacterCodeType] = { + # 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 840f6bd8e652..05f6d8aa02b3 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,95 +44,93 @@ 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"]): + # num is a manager-like instance (not necessarily a + # FigureManagerBase subclass) + 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): - # this is need to ensure that gc is available in corner cases - # where modules are being torn down after install with easy_install - import gc # noqa + """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/_style_helpers.py b/lib/matplotlib/_style_helpers.py new file mode 100644 index 000000000000..9b98d90593f9 --- /dev/null +++ b/lib/matplotlib/_style_helpers.py @@ -0,0 +1,51 @@ +import collections.abc +import itertools + +import numpy as np + +import matplotlib.cbook as cbook +import matplotlib.colors as mcolors +import matplotlib.lines as mlines + + +def check_non_empty(key, value): + """Raise a TypeError if an empty sequence is passed""" + if (not cbook.is_scalar_or_string(value) and + isinstance(value, collections.abc.Sized) and len(value) == 0): + raise TypeError(f'{key} must not be an empty sequence') + + +def style_generator(kw): + """ + Helper for handling style sequences (e.g. facecolor=['r', 'b', 'k']) within plotting + methods that repeatedly call other plotting methods (e.g. hist, stackplot). Remove + style keywords from the given dictionary. Return the reduced dictionary together + with a generator which provides a series of dictionaries to be used in each call to + the wrapped function. + """ + kw_iterators = {} + remaining_kw = {} + for key, value in kw.items(): + if key in ['facecolor', 'edgecolor']: + if value is None or cbook._str_lower_equal(value, 'none'): + kw_iterators[key] = itertools.repeat(value) + else: + check_non_empty(key, value) + kw_iterators[key] = itertools.cycle(mcolors.to_rgba_array(value)) + + elif key in ['hatch', 'linewidth']: + check_non_empty(key, value) + kw_iterators[key] = itertools.cycle(np.atleast_1d(value)) + + elif key == 'linestyle': + check_non_empty(key, value) + kw_iterators[key] = itertools.cycle(mlines._get_dash_patterns(value)) + + else: + remaining_kw[key] = value + + def style_gen(): + while True: + yield {key: next(val) for key, val in kw_iterators.items()} + + return remaining_kw, style_gen() diff --git a/lib/matplotlib/_text_helpers.py b/lib/matplotlib/_text_helpers.py new file mode 100644 index 000000000000..0ebbf3ac139d --- /dev/null +++ b/lib/matplotlib/_text_helpers.py @@ -0,0 +1,50 @@ +""" +Low-level text helper utilities. +""" + +from __future__ import annotations + +from collections.abc import Iterator + +from . import _api +from .ft2font import FT2Font, CharacterCodeType, LayoutItem, LoadFlags + + +def warn_on_missing_glyph(codepoint: CharacterCodeType, fontnames: str): + _api.warn_external( + f"Glyph {codepoint} " + f"({chr(codepoint).encode('ascii', 'namereplace').decode('ascii')}) " + f"missing from font(s) {fontnames}.") + + +def layout(string: str, font: FT2Font, *, + features: tuple[str] | None = None, + language: str | tuple[tuple[str, int, int], ...] | None = None + ) -> Iterator[LayoutItem]: + """ + 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. + features : tuple of str, optional + The font features to apply to the text. + language : str, optional + The language of the text in a format accepted by libraqm, namely `a BCP47 + language code `_. + + Yields + ------ + LayoutItem + """ + for raqm_item in font._layout(string, LoadFlags.NO_HINTING, + features=features, language=language): + raqm_item.ft_object.load_glyph(raqm_item.glyph_index, + flags=LoadFlags.NO_HINTING) + yield raqm_item 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..b4ee5edb233c --- /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.getitem_checked({'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 2939614fda4a..7146dc28fcc9 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -1,315 +1,438 @@ -# 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 platform -import sys -import itertools +import abc +import base64 +import collections 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/questions/24130623/using-python-subprocess-popen-cant-prevent-exe-stopped-working-prompt -if platform.system() == 'Windows': - CREATE_NO_WINDOW = 0x08000000 - subprocess_creation_flags = CREATE_NO_WINDOW -else: - # Apparently None won't work here - subprocess_creation_flags = 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 ) - - -# A registry for available MovieWriter classes -class MovieWriterRegistry(object): +# window. See for example https://stackoverflow.com/q/24130623/ +subprocess_creation_flags = ( + subprocess.CREATE_NO_WINDOW if sys.platform == 'win32' else 0) + + +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.""" + 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.""" + _api.check_in_list(self._registered, writer=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, - creationflags=subprocess_creation_flags) + _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, - creationflags=subprocess_creation_flags) - p.communicate() - return True - except OSError: + """Return whether a MovieWriter subclass is actually available.""" + if sys.platform == 'emscripten': return False + 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 @@ -317,6 +440,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): @@ -324,257 +451,441 @@ 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 @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 + + Parameters + ---------- + *args, **kwargs + All arguments are forwarded to `FileMovieWriter`. See + `FileMovieWriter` for a list of all possible parameters. + """ + 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 - + 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] -# Base class of avconv information. AVConv has identical arguments to -# FFMpeg -class AVConvBase(FFMpegBase): - exec_key = 'animation.avconv_path' - args_key = 'animation.avconv_args' +# Base class for animated GIFs with ImageMagick +class ImageMagickBase: + """ + Mixin class for ImageMagick output. -# Combine AVConv options with pipe-based writing -@writers.register('avconv') -class AVConvWriter(AVConvBase, FFMpegWriter): - pass + 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. + """ + _exec_key = 'animation.convert_path' + _args_key = 'animation.convert_args' -# Combine AVConv options with file-based writing -@writers.register('avconv_file') -class AVConvFileWriter(AVConvBase, FFMpegFileWriter): - pass + def _supports_transparency(self): + suffix = Path(self.outfile).suffix + return suffix in {'.apng', '.avif', '.gif', '.webm', '.webp'} + 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, + ] -# 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' + @classmethod + def bin_path(cls): + binpath = super().bin_path() + if binpath == 'convert': + binpath = mpl._get_executable_info('magick').executable + return binpath - # Mencoder only allows certain keys, other ones cause the program - # to fail. - allowed_metadata = ['name', 'artist', 'genre', 'subject', 'copyright', - 'srcform', 'comment'] + @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 - # 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'] - @property - def output_args(self): - self._remap_metadata() - lavcopts = {'vcodec': self.codec} - if self.bitrate > 0: - lavcopts.update(vbitrate=self.bitrate) - args = ['-o', self.outfile, '-ovc', 'lavc', '-lavcopts', - ':'.join(itertools.starmap('{0}={1}'.format, - lavcopts.items()))] - 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. + Frames are streamed directly to ImageMagick via a pipe and written + in a single pass. + """ -# 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 + 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'] +# Combine ImageMagick options with temp file-based writing +@writers.register('imagemagick_file') +class ImageMagickFileWriter(ImageMagickBase, FileMovieWriter): + """ + File-based animated gif writer. - 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 + Frames are written to temporary files on disk and then stitched + together at the end. + """ + supported_formats = ['png', 'jpeg', 'tiff', 'raw', 'rgba'] + input_names = property( + lambda self: f'{self.temp_prefix}*.{self.frame_format}') -# Base class for animated GIFs with convert utility -class ImageMagickBase(object): - exec_key = 'animation.convert_path' - args_key = 'animation.convert_args' - @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: + """ + Abstract base class for Animations. + + .. 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 + 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 + """ + + def __init__(self, fig, event_source, blit=False): + self._draw_was_started = False - *blit* is a boolean that controls whether blitting is used to optimize - drawing. - ''' - def __init__(self, fig, event_source=None, blit=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 @@ -587,9 +898,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. @@ -602,18 +911,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. @@ -625,158 +946,206 @@ 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 : `AbstractMovieWriter` subclass or str, default: :rc:`animation.writer` + The writer used to grab the frames and create the movie file. + This can be an instance of an `AbstractMovieWriter` subclass or a + string. The builtin writers are + + ================== ============================== + str class + ================== ============================== + 'ffmpeg' `.FFMpegWriter` + 'ffmpeg_file' `.FFMpegFileWriter` + 'imagemagick' `.ImageMagickWriter` + 'imagemagick_file' `.ImageMagickFileWriter` + 'pillow' `.PillowWriter` + 'html' `.HTMLWriter` + ================== ============================== + + 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 + + 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 codec is None: - codec = rcParams['animation.codec'] + Example code to write the progress to stdout:: - if bitrate is None: - bitrate = rcParams['animation.bitrate'] + 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. @@ -788,12 +1157,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() @@ -807,13 +1176,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. @@ -825,46 +1194,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 @@ -876,90 +1263,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'') @@ -753,106 +532,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: @@ -862,1500 +644,1900 @@ 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: + if len(x.dtype.descr) == 1: + # Arrays with dtype 'object' get returned here. + # For example the 'c' kwarg of scatter, which supports multiple types. + # `plt.scatter([3, 4], [2, 5], c=[(1, 0, 0), 'y'])` + return x + else: + # In case of a dtype with multiple fields + # for example image data using a MultiNorm + try: + mask = np.empty(x.shape, dtype=np.dtype('bool, '*len(x.dtype.descr))) + for dd, dm in zip(x.dtype.descr, mask.dtype.descr): + mask[dm[0]] = ~np.isfinite(x[dd[0]]) + xm = np.ma.array(x, mask=mask, 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))))) - - def __call__(self, match): - """ Handler invoked for each regex *match* """ - return self[match.group(0)] - - def xlat(self, text): - """ Translate *text*, returns the modified text. """ - return self._make_regex().sub(self, text) + It is often useful to pass in ``gc.garbage`` to find the cycles that are + preventing some objects from being garbage collected. + 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 soundex(name, len=4): - """ soundex module conforming to Odell-Russell algorithm """ - - # digits holds the soundex values for the alphabet - soundex_digits = '01230120022455012623010202' - sndx = '' - fc = '' + def print_path(path): + for i, step in enumerate(path): + # next "wraps around" + next = path[(i + 1) % len(path)] - # 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 + 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") - # Replace first digit with first letter - sndx = fc + sndx[1:] + def recurse(obj, start, all, current_path): + if show_progress: + outstream.write("%d\r" % len(all)) - # Remove all 0s from the soundex code - sndx = sndx.replace('0', '') + all[id(obj)] = None - # Return soundex code truncated or 0-padded to len characters - return (sndx + (len * '0'))[:len] + 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) + # 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 -class Null(object): - """ Null objects always and reliably "do nothing." """ + # We haven't seen this object before, so recurse + elif id(referent) not in all: + recurse(referent, start, all, current_path + [obj]) - 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)) + + 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. - 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 + 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, *, include_self=True): + """ + Return all the items joined with *a*. -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 + *a* is included in the list if *include_self* is True. + """ + siblings = self._mapping.get(a, [a]) + result = sorted(siblings, key=self._ordering.get) + if not include_self: + result.remove(a) return result -get_realpath_and_stat = GetRealpathAndStat() -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`.""" + def __init__(self, grouper): self._grouper = grouper + def __contains__(self, item): return item in self._grouper + def __iter__(self): return iter(self._grouper) -class RingBuffer(object): - """ class that implements a not-yet-full buffer """ - def __init__(self, size_max): - self.max = size_max - self.data = [] + def joined(self, a, b): + """ + Return whether *a* and *b* are members of the same set. + """ + return self._grouper.joined(a, b) - 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 get_siblings(self, a, *, include_self=True): + """ + Return all the items joined with *a*. - def get(self): - """ return list of elements in correct order """ - return self.data[self.cur:] + self.data[:self.cur] + *a* is included in the list if *include_self* is True. + """ + return self._grouper.get_siblings(a, include_self=include_self) - 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 (TypeError, ValueError): + 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 '' + Find all masked and/or non-finite points in a set of arguments, + and return the arguments as masked arrays with a common mask. - match = _find_dedent_regex.match(s) - if match is None: - return s + Arguments can be in any of 5 categories: - # 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 + 1) 1-D masked arrays + 2) 1-D ndarrays + 3) ndarrays with more than one dimension + 4) other non-string iterables + 5) anything else - # 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 + 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. - result = unindent.sub("\n", s).strip() - return result + 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. + All input arguments that are not passed unchanged are returned + as masked arrays if any masked points are found, otherwise as + ndarrays. -def listFiles(root, patterns='*', recurse=1, return_folders=0): """ - Recursively list files + 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 - from Parmar and Martelli in the Python Cookbook + +def _broadcast_with_masks(*args, compress=False): """ - import os.path - import fnmatch - # Expand patterns from semicolon-separated string to list - pattern_list = patterns.split(';') - results = [] + Broadcast inputs, combining all masked arrays. - 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 + 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. + + 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 - return results +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`. -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 - """ - files = [] + Parameters + ---------- + X : array-like + Data that will be represented in the boxplots. Should have 2 or + fewer dimensions. - 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) + whis : float or (float, float), default: 1.5 + The position of the whiskers. - return [f for f in files if not os.path.islink(f)] + 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. + 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. -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 + 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. + Beyond the whiskers, data are considered outliers and are plotted as + individual points. -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() + bootstrap : int, optional + Number of times the confidence intervals around the median + should be bootstrapped (percentile method). + labels : list of str, optional + Labels for each dataset. Length must be compatible with + dimensions of *X*. -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 + 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. + Returns + ------- + list of dict + A list of dictionaries containing the results for each column + of data. Keys of each dictionary are the following: -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 + ======== =================================== + 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 + ======== =================================== + Notes + ----- + Non-bootstrapping approach to confidence interval uses Gaussian-based + asymptotic approximation: -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 + .. math:: + \mathrm{med} \pm 1.57 \times \frac{\mathrm{iqr}}{\sqrt{N}} -def allpairs(x): + General approach from: + McGill, R., Tukey, J.W., and Larsen, W.A. (1978) "Variations of + Boxplots", The American Statistician, 32:12-16. """ - return all possible pairs in sequence *x* - Condensed by Alex Martelli from this thread_ on c.l.python + def _bootstrap_median(data, N=5000): + # determine 95% confidence intervals of the median + M = len(data) + percentiles = [2.5, 97.5] - .. _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:]] + bs_index = np.random.randint(M, size=(N, M)) + bsData = data[bs_index] + estimate = np.median(bsData, axis=1, overwrite_input=True) + CI = np.percentile(estimate, percentiles) + return CI -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 = [] + 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: - 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) + 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 -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 - """ + # output is a list of dicts + bxpstats = [] - def __init__(self, default=None): - self.clear() - self._default = default + # convert X to a list of lists + X = _reshape_2D(X, "X") - def __call__(self): - 'return the current element, or None' - if not len(self._elements): - return self._default - else: - return self._elements[self._pos] + 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 __len__(self): - return self._elements.__len__() + input_whis = whis + for ii, (x, label) in enumerate(zip(X, labels)): - def __getitem__(self, ind): - return self._elements.__getitem__(ind) + # empty dict + stats = {} + if label is not None: + stats['label'] = label - 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() + # restore whis to the input values in case it got changed in the loop + whis = input_whis - def back(self): - 'move the position back and return the current element' - if self._pos > 0: - self._pos -= 1 - return self() + # note tricksiness, append up here and then mutate below + bxpstats.append(stats) - 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() + # 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 - 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() + # up-convert to an array, just to be safe + x = np.ma.asarray(x) + x = x.data[~x.mask].ravel() - def empty(self): - return len(self._elements) == 0 + # arithmetic mean + stats['mean'] = np.mean(x) - def clear(self): - 'empty the stack' - self._pos = -1 - self._elements = [] + # medians and quartiles + q1, med, q3 = np.percentile(x, [25, 50, 75]) - def bubble(self, o): - """ - raise *o* to the top of the stack and return *o*. *o* must be - in the stack - """ + # interquartile range + stats['iqr'] = q3 - q1 + if stats['iqr'] == 0 and autorange: + whis = (0, 100) - 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 + # conf. interval around median + stats['cilo'], stats['cihi'] = _compute_conf_interval( + x, med, stats['iqr'], bootstrap + ) - 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) + # 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 popall(seq): - 'empty a list' - for i in xrange(len(seq)): - seq.pop() + # 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 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] + # add in the remaining stats + stats['q1'], stats['med'], stats['q3'] = q1, med, q3 + return bxpstats -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)]) +#: 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 restrict_dict(d, keys): + +def contiguous_regions(mask): """ - Return a dictionary that contains those keys that appear in both - d and keys, with values from d. + Return a list of (ind0, ind1) such that ``mask[ind0:ind1].all()`` is + True and we cover all such regions. """ - return dict([(k, v) for (k, v) in six.iteritems(d) if k in keys]) + mask = np.asarray(mask, dtype=bool) + if not mask.size: + return [] -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 + # Find the indices of region changes, and correct offset + idx, = np.nonzero(mask[:-1] != mask[1:]) + idx += 1 -_safezip_msg = 'In safezip, len(args[0])=%d but len(args[%d])=%d' + # 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)) -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)) + return list(zip(idx[::2], idx[1::2])) -def issubclass_safe(x, klass): - 'return issubclass(x, klass) and return False on a TypeError' +def is_math_text(s): + """ + Return whether the string *s* contains math expressions. - try: - return issubclass(x, klass) - except TypeError: - return False + 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 safe_masked_invalid(x): - x = np.asanyarray(x) - try: - xm = np.ma.masked_invalid(x, copy=False) - xm.shrink_mask() - except TypeError: +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 - return xm -class MemoryMonitor(object): - def __init__(self, nmax=20000): - self._nmax = nmax - self._mem = np.zeros((self._nmax,), np.int32) - self.clear() - - 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 xy(self, i0=0, isub=1): - x = np.arange(i0, self._n, isub) - return x, self._mem[i0:self._n:isub] - - 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 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 )") + # Iterate over columns for ndarrays. + if isinstance(X, np.ndarray): + X = X.transpose() + + 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: - outstream.write(repr(step)) - outstream.write(" ->\n") - outstream.write("\n") + 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 - def recurse(obj, start, all, current_path): - if show_progress: - outstream.write("%d\r" % len(all)) - all[id(obj)] = None +def violin_stats(X, method=("GaussianKDE", "scott"), points=100, quantiles=None): + """ + Return a list of dictionaries of data which can be used to draw a series + of violin plots. - 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) + See the ``Returns`` section below to view the required keys of the + dictionary. - # 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 + Users can skip this function and pass a user-defined set of dictionaries + with the same keys to `~.axes.Axes.violin` instead of using Matplotlib + to do the calculations. See the *Returns* section below for the keys + that must be present in the dictionaries. - # We haven't seen this object before, so recurse - elif id(referent) not in all: - recurse(referent, start, all, current_path + [obj]) + Parameters + ---------- + X : 1D array or sequence of 1D arrays or 2D array + Sample data that will be used to produce the gaussian kernel density + estimates. Possible values: - for obj in objects: - outstream.write("Examining: %r\n" % (obj,)) - recurse(obj, obj, {}, []) + - 1D array: Statistics are computed for that array. + - sequence of 1D arrays: Statistics are computed for each array in the sequence. + - 2D array: Statistics are computed for each column in the array. + method : (name, bw_method) or callable, + The method used to calculate the kernel density estimate for each + column of data. Valid values: -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. + - a tuple of the form ``(name, bw_method)`` where *name* currently must + always be ``"GaussianKDE"`` and *bw_method* is the method used to + calculate the estimator bandwidth. Supported values are 'scott', + 'silverman' or a float or a callable. If a float, this will be used + directly as `!kde.factor`. If a callable, it should take a + `matplotlib.mlab.GaussianKDE` instance as its only parameter and + return a float. - 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. + - a callable with the signature :: - The objects being joined must be hashable and weak-referenceable. + def method(data: ndarray, coords: ndarray) -> ndarray - For example: + It should return the KDE of *data* evaluated at *coords*. - >>> 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)] + .. versionadded:: 3.11 + Support for ``(name, bw_method)`` tuple. - def __contains__(self, item): - return ref(item) in self._mapping + points : int, default: 100 + Defines the number of points to evaluate each of the gaussian kernel + density estimates at. - 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) + 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. - 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)]) + Returns + ------- + list of dict + A list of dictionaries containing the results for each column of data. + The dictionaries contain at least the following: - 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 + - 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. + """ + if isinstance(method, tuple): + name, bw_method = method + if name != "GaussianKDE": + raise ValueError(f"Unknown KDE method name {name!r}. The only supported " + 'named method is "GaussianKDE"') - self.clean() + def _kde_method(x, coords): + # fallback gracefully if the vector contains only one value + if np.all(x[0] == x): + return (x[0] == coords).astype(float) + kde = mlab.GaussianKDE(x, bw_method) + return kde.evaluate(coords) - def joined(self, a, b): - """ - Returns True if *a* and *b* are members of the same set. - """ - self.clean() + method = _kde_method - mapping = self._mapping - try: - return mapping[ref(a)] is mapping[ref(b)] - except KeyError: - return False + # List of dictionaries describing each of the violins. + vpstats = [] - def __iter__(self): - """ - Iterate over each of the disjoint sets as a list. + # Want X to be a list of data sequences + X = _reshape_2D(X, "X") - The iterator is invalid if interleaved with calls to join(). - """ - self.clean() + # 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) - class Token: - pass - token = Token() + # 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") - # 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) + # Zip x and quantiles + for (x, q) in zip(X, quantiles): + # Dictionary of results for this distribution + stats = {} - # Cleanup the tokens - for group in six.itervalues(self._mapping): - if group[-1] is token: - del group[-1] + # Calculate basic stats for the distribution + min_val = np.min(x) + max_val = np.max(x) + quantile_val = np.percentile(x, 100 * q) - def get_siblings(self, a): - """ - Returns all of the items joined with *a*, including itself. - """ - self.clean() + # Evaluate the kernel density estimate + coords = np.linspace(min_val, max_val, points) + stats['vals'] = method(x, coords) + stats['coords'] = coords - siblings = self._mapping.get(ref(a), [ref(a)]) - return [x() for x in siblings] + # 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) + # Append to output + vpstats.append(stats) -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) + return vpstats -def delete_masked_points(*args): +def pts_to_prestep(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 pre-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 + beginning 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_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 - A vastly simpler version of this function was originally - written as a helper for Axes.scatter(). +def pts_to_poststep(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 post-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 + 1`` points, which when + connected linearly give a step function which changes values at the end 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 + 1``. For + ``N=0``, the length will be 0. - ======== =================================== - 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 - cihi upper notch around the median - whislo end of the lower whisker - whishi end of the upper whisker - fliers outliers - ======== =================================== - - Notes - ----- - Non-bootstrapping approach to confidence interval uses Gaussian-based - asymptotic approximation: + 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 - .. math:: - \mathrm{med} \pm 1.57 \\times \\frac{\mathrm{iqr}}{\sqrt{N}} +def pts_to_midstep(x, *args): + """ + Convert continuous line to mid-steps. - General approach from: - McGill, R., Tukey, J.W., and Larsen, W.A. (1978) "Variations of - Boxplots", The American Statistician, 32:12-16. + 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 + The x location of the steps. May be empty. - def _bootstrap_median(data, N=5000): - # determine 95% confidence intervals of the median - M = len(data) - percentiles = [2.5, 97.5] + y1, ..., yp : array + y arrays to be turned into steps; all must be the same length as + ``x``. - ii = np.random.randint(M, size=(N, M)) - bsData = x[ii] - estimate = np.median(bsData, axis=1, overwrite_input=True) + 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``. - CI = np.percentile(estimate, percentiles) - return CI + 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 - 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: - N = len(data) - notch_min = med - 1.57 * iqr / np.sqrt(N) - notch_max = med + 1.57 * iqr / np.sqrt(N) +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} - return notch_min, notch_max - # output is a list of dicts - bxpstats = [] +def index_of(y): + """ + A helper function to create reasonable x values for the given *y*. - # convert X to a list of lists - X = _reshape_2D(X) + This is used for plotting (x, y) if x values are not explicitly given. - ncols = len(X) - if labels is None: - labels = repeat(None) - elif len(labels) != ncols: - raise ValueError("Dimensions of labels and X must be compatible") + First try ``y.index`` (assuming *y* is a `pandas.Series`), if that + fails, use ``range(len(y))``. - input_whis = whis - for ii, (x, label) in enumerate(zip(X, labels), start=0): + This will be extended in the future to deal with more types of + labeled data. - # empty dict - stats = {} - if label is not None: - stats['label'] = label + Parameters + ---------- + y : float or array-like - # restore whis to the input values in case it got changed in the loop - whis = input_whis + 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') - # 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['cihi'] = np.nan - stats['whislo'] = np.nan - stats['whishi'] = np.nan - stats['med'] = np.nan - continue +def safe_first_element(obj): + """ + Return the first element in *obj*. - # up-convert to an array, just to be safe - x = np.asarray(x) + 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)) - # arithmetic mean - stats['mean'] = np.mean(x) - # medians and quartiles - q1, med, q3 = np.percentile(x, [25, 50, 75]) +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. - # interquartile range - stats['iqr'] = q3 - q1 - if stats['iqr'] == 0: - whis = 'range' + This is a method for internal use. - # conf. interval around median - stats['cilo'], stats['cihi'] = _compute_conf_interval( - x, med, stats['iqr'], bootstrap - ) + 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 - # 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]) + 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) - # 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) - # 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) +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) - # compute a single array of outliers - stats['fliers'] = np.hstack([ - np.compress(x < stats['whislo'], x), - np.compress(x > stats['whishi'], x) - ]) - # add in the remaining stats - stats['q1'], stats['med'], stats['q3'] = q1, med, q3 +def _resize_sequence(seq, N): + """ + Trim the given sequence to exactly N elements. + If there are more elements in the sequence, cut it. + If there are less elements in the sequence, repeat them. - return bxpstats + 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)) -# FIXME I don't think this is used anywhere -def unmasked_index_ranges(mask, compressed=True): +def normalize_kwargs(kw, alias_mapping=None): """ - Find index ranges where *mask* is *False*. + Helper function to normalize kwarg inputs. + + 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``. - *mask* will be flattened if it is not already 1-D. + alias_mapping : Artist subclass or Artist instance + A mapping between a canonical name to a list of aliases, in order of + precedence from lowest to highest. - 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. + If the canonical value is not in the list it is assumed to have the + highest priority. - Example:: + 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 - 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,]] + # deal with default value of alias_mapping + if (isinstance(alias_mapping, type) and issubclass(alias_mapping, Artist) + or isinstance(alias_mapping, Artist)): + alias_to_prop = getattr(alias_mapping, "_alias_to_prop", {}) + else: + if alias_mapping is None: + alias_mapping = {} + _api.warn_deprecated("3.11", message=( + "Passing a dict or None as alias_mapping to normalize_kwargs is " + "deprecated since %(since)s and support will be removed " + "%(removal)s; pass an Artist instance or type instead.")) + # Convert old format to new format. + alias_to_prop = {alias: prop for prop, aliases in alias_mapping.items() + for alias in aliases} + + if kw is None: + return {} - y.compressed()[ii[1,0]:ii[1,1]] - # returns array [3,4,] + canonicalized = {alias_to_prop.get(k, k): v for k, v in kw.items()} + if len(canonicalized) == len(kw): + return canonicalized - ii = unmasked_index_ranges(ma.getmaskarray(y), compressed=False) - # returns array [[0, 2], [3, 5]] + canonical_to_seen = {} + for k in kw: + canonical = alias_to_prop.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 - 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. +@contextlib.contextmanager +def _lock_path(path): """ - 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) + Context manager for locking a path. -# a dict to cross-map linestyle arguments -_linestyles = [('-', 'solid'), - ('--', 'dashed'), - ('-.', 'dashdot'), - (':', 'dotted')] + Usage:: -ls_mapper = dict(_linestyles) -ls_mapper.update([(ls[1], ls[0]) for ls in _linestyles]) + with _lock_path(path): + ... + Another thread or process that attempts to lock the same path will wait + until this context manager is exited. -def align_iterators(func, *iterables): + The lock is implemented by creating a temporary file in the parent + directory, so that directory must exist and be writable. """ - This generator takes a bunch of iterables that are ordered by func - It sends out ordered tuples:: + 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() - (func(row), [rows from all iterators matching func(row)]) - It is used by :func:`matplotlib.mlab.recs_join` to join record arrays +def _topmost_artist( + artists, + _cached_max=functools.partial(max, key=operator.attrgetter("zorder"))): """ - class myiter: - def __init__(self, it): - self.it = it - self.key = self.value = None - self.iternext() + Get the topmost artist of a list. - 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 + 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)) -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 _str_equal(obj, s): + """ + Return whether *obj* is a string equal to string *s*. - dollar_count = s.count(r'$') - s.count(r'\$') - even_dollars = (dollar_count > 0 and dollar_count % 2 == 0) + 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 == s - return even_dollars +def _str_lower_equal(obj, s): + """ + Return whether *obj* is a string equal, when lowercased, to string *s*. -def _reshape_2D(X): + 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. """ - Converts a non-empty list or an ndarray of two or fewer dimensions - into a list of iterable objects so that in + return isinstance(obj, str) and obj.lower() == s - for v in _reshape_2D(X): - v is iterable and can be used to instantiate a 1D array. +def _array_perimeter(arr): """ - 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") + Get the elements on the perimeter of *arr*. - if not hasattr(X[0], '__len__'): - X = [X] - else: - X = [np.ravel(x) for x in X] + Parameters + ---------- + arr : ndarray, shape (M, N) + The input array. + + 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], ...] + + 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]) + """ + # 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], + )) - return X +def _unfold(arr, axis, size, step): + """ + Append an extra dimension containing sliding windows along *axis*. -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. + All windows are of size *size* and begin with every *step* elements. Parameters ---------- - X : array-like - Sample data that will be used to produce the gaussian kernel density - estimates. Must have 2 or fewer dimensions. + 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. - 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. + Returns + ------- + ndarray, shape (N_1, ..., 1 + (N_axis-size)/step, ..., N_k, size) - points : scalar, default = 100 - Defines the number of points to evaluate each of the gaussian kernel - density estimates at. + 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 : 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. + """ + 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) + + +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)) + + +def _check_and_log_subprocess(command, logger, **kwargs): """ - def __call__(self, containing_class, class_name): - nested_class = getattr(containing_class, class_name) + Run *command*, returning its stdout output if it succeeds. - # make an instance of a simple object (this one will do), for which we - # can change the __class__ later on. - nested_instance = _NestedClassGetter() + If it fails (exits with nonzero return code), raise an exception whose text + includes the failed command and captured stdout and stderr output. - # 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 + Regardless of the return code, the command is logged at DEBUG level on + *logger*. In case of success, the output is likewise logged. + """ + 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 -class _InstanceMethodPickler(object): +def _setup_new_guiapp(): """ - Pickle cannot handle instancemethod saving. _InstanceMethodPickler - provides a solution to this. + Perform OS-dependent setup when Matplotlib creates a new GUI application. """ - 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__ + # 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 _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' + + +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*. + """ + # For inf or nan, the precision doesn't matter. + if not math.isfinite(value): + return 0 + 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. + return max( + 0, + (math.floor(math.log10(abs(value))) + 1 if value else 1) + - math.floor(math.log10(delta))) + + +def _unikey_or_keysym_to_mplkey(unikey, keysym): + """ + Convert a Unicode key or X keysym to a Matplotlib key name. - def get_instancemethod(self): - return getattr(self.parent_obj, self.instancemethod_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 -# 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. +@functools.cache +def _make_class_factory(mixin_class, fmt, attr_name=None): + """ + Return a function that creates picklable classes inheriting from a mixin. -try: - np.copyto -except AttributeError: - _putmask = np.putmask -else: - def _putmask(a, mask, values): - return np.copyto(a, values, where=mask) + 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_mlx_array(x): + """Return whether *x* is a MLX Array.""" + try: + # We're intentionally not attempting to import mlx. If somebody + # has created a mlx array, mlx should already be in sys.modules. + tp = sys.modules.get("mlx.core").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) \ + or _is_mlx_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..4a9fcaa32e67 --- /dev/null +++ b/lib/matplotlib/cbook.pyi @@ -0,0 +1,181 @@ +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, + TypeVar, + overload, +) +from collections.abc import Sequence + +_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: ... + @overload + def disconnect(self, cid_or_func: int) -> None: ... + @overload + def disconnect(self, cid_or_func: Callable, *, signal: Any | None = ...) -> 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, *, include_self: bool = True) -> 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, *, include_self: bool = True) -> 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: tuple[Literal["GaussianKDE"], Literal["scott", "silverman"] | float | Callable] | 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: 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 9c3bc175632b..8bf28aa166aa 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -1,359 +1,241 @@ """ -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 +.. seealso:: + :doc:`/gallery/color/colormap_reference` for a list of builtin colormaps. -def _generate_cmap(name, lutsize): - """Generates the requested cmap from it's name *name*. The lut size is - *lutsize*.""" + :ref:`colormap-manipulation` for examples of how to make + colormaps. - spec = datad[name] + :ref:`colormaps` an in-depth discussion of choosing + colormaps. - # Generate the colormap object. - if 'red' in spec: - return colors.LinearSegmentedColormap(name, spec, lutsize) - else: - return colors.LinearSegmentedColormap.from_list(name, spec, lutsize) - -LUTSIZE = mpl.rcParams['image.lut'] - -# 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(): """ - Add a colormap to the set recognized by :func:`get_cmap`. - - It can be used in two ways:: - - register_cmap(name='swirly', cmap=swirly_cmap) - - register_cmap(name='choppy', data=choppydata, lut=128) - - 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*. + Generate a dict mapping standard colormap names to standard colormaps, as + well as the reversed colormaps. + """ + 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) - In the second case, the three arguments are passed to - the :class:`~matplotlib.colors.LinearSegmentedColormap` initializer, - and the resulting colormap is registered. + def __getitem__(self, item): + cmap = _api.getitem_checked(self._cmaps, colormap=item, _error_cls=KeyError) + return cmap.copy() - """ - if name is None: - try: - name = cmap.name - except AttributeError: - raise ValueError("Arguments must include a name or a Colormap") + def __iter__(self): + return iter(self._cmaps) - if not cbook.is_string_like(name): - raise ValueError("Colormap name must be a string") + def __len__(self): + return len(self._cmaps) - if isinstance(cmap, colors.Colormap): - cmap_d[name] = cmap - return + def __str__(self): + return ('ColormapRegistry; available colormaps:\n' + + ', '.join(f"'{name}'" for name in self)) - # 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 + def __call__(self): + """ + Return a list of the registered colormap names. + 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) -def get_cmap(name=None, lut=None): - """ - Get a colormap instance, defaulting to rc values if *name* is None. + def register(self, cmap, *, name=None, force=False): + """ + Register a new colormap. - Colormaps added with :func:`register_cmap` take precedence over - built-in colormaps. + 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``. - If *name* is a :class:`matplotlib.colors.Colormap` instance, it will be - returned. + 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. - 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'] + Parameters + ---------- + cmap : matplotlib.colors.Colormap + The colormap to register. - if isinstance(name, colors.Colormap): - return name + name : str, optional + The name for the colormap. If not given, ``cmap.name`` is used. - 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()))) + 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.") -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. + # Warn that we are updating an already existing colormap + _api.warn_external(f"Overwriting the cmap {name!r} " + "that was already in the registry.") - """ - def __init__(self, norm=None, cmap=None): - r""" + 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 - 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. + def unregister(self, name): """ + Remove a colormap from the registry. - self.callbacksSM = cbook.CallbackRegistry() + You cannot remove built-in colormaps. - 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} - - 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): - """ - set the norm limits for image scaling; if *vmin* is a length2 - sequence, interpret it as ``(vmin, vmax)`` which is used to - support setp + If the named colormap is not registered, returns with no error, raises + if you try to de-register a default colormap. - 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 + .. warning:: - if vmin is not None: - self.norm.vmin = vmin - if vmax is not None: - self.norm.vmax = vmax - self.changed() + 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. - def set_cmap(self, cmap): - """ - set the colormap for luminance data + Parameters + ---------- + name : str + The name of the colormap to be removed. - 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 + Raises + ------ + ValueError + If you try to remove a default built-in colormap. """ - if self._A is None: - raise TypeError('You must first set_array for mappable') - self.norm.autoscale(self._A) - self.changed() + if name in self._builtin_cmaps: + raise ValueError(f"cannot unregister {name!r} which is a builtin " + "colormap.") + self._cmaps.pop(name, None) - def autoscale_None(self): + def get_cmap(self, cmap): """ - 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() + Return a color map specified through *cmap*. - 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 + Parameters + ---------- + cmap : str or `~matplotlib.colors.Colormap` or None - 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 + - if a `.Colormap`, return it + - if a string, look it up in ``mpl.colormaps`` + - if None, return the Colormap defined in :rc:`image.cmap` - def changed(self): + Returns + ------- + Colormap """ - Call this whenever the mappable is changed to notify all the - callbackSM listeners to the 'changed' signal - """ - self.callbacksSM.process('changed', self) - - for key in self.update_dict: - self.update_dict[key] = True + # get the default color map + if cmap is None: + return self[mpl.rcParams["image.cmap"]] + + # 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)}' + ) + + +# 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) + +_multivar_colormaps = ColormapRegistry(multivar_cmaps) + +_bivar_colormaps = ColormapRegistry(bivar_cmaps) diff --git a/lib/matplotlib/cm.pyi b/lib/matplotlib/cm.pyi new file mode 100644 index 000000000000..f4b9fb9ea8dd --- /dev/null +++ b/lib/matplotlib/cm.pyi @@ -0,0 +1,206 @@ +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 + +magma: colors.Colormap +inferno: colors.Colormap +plasma: colors.Colormap +viridis: colors.Colormap +cividis: colors.Colormap +twilight: colors.Colormap +twilight_shifted: colors.Colormap +turbo: colors.Colormap +berlin: colors.Colormap +managua: colors.Colormap +vanimo: colors.Colormap +Blues: colors.Colormap +BrBG: colors.Colormap +BuGn: colors.Colormap +BuPu: colors.Colormap +CMRmap: colors.Colormap +GnBu: colors.Colormap +Greens: colors.Colormap +Greys: colors.Colormap +OrRd: colors.Colormap +Oranges: colors.Colormap +PRGn: colors.Colormap +PiYG: colors.Colormap +PuBu: colors.Colormap +PuBuGn: colors.Colormap +PuOr: colors.Colormap +PuRd: colors.Colormap +Purples: colors.Colormap +RdBu: colors.Colormap +RdGy: colors.Colormap +RdPu: colors.Colormap +RdYlBu: colors.Colormap +RdYlGn: colors.Colormap +Reds: colors.Colormap +Spectral: colors.Colormap +Wistia: colors.Colormap +YlGn: colors.Colormap +YlGnBu: colors.Colormap +YlOrBr: colors.Colormap +YlOrRd: colors.Colormap +afmhot: colors.Colormap +autumn: colors.Colormap +binary: colors.Colormap +bone: colors.Colormap +brg: colors.Colormap +bwr: colors.Colormap +cool: colors.Colormap +coolwarm: colors.Colormap +copper: colors.Colormap +cubehelix: colors.Colormap +flag: colors.Colormap +gist_earth: colors.Colormap +gist_gray: colors.Colormap +gist_heat: colors.Colormap +gist_ncar: colors.Colormap +gist_rainbow: colors.Colormap +gist_stern: colors.Colormap +gist_yarg: colors.Colormap +gnuplot: colors.Colormap +gnuplot2: colors.Colormap +gray: colors.Colormap +hot: colors.Colormap +hsv: colors.Colormap +jet: colors.Colormap +nipy_spectral: colors.Colormap +ocean: colors.Colormap +pink: colors.Colormap +prism: colors.Colormap +rainbow: colors.Colormap +seismic: colors.Colormap +spring: colors.Colormap +summer: colors.Colormap +terrain: colors.Colormap +winter: colors.Colormap +Accent: colors.Colormap +Dark2: colors.Colormap +okabe_ito: colors.Colormap +Paired: colors.Colormap +Pastel1: colors.Colormap +Pastel2: colors.Colormap +Set1: colors.Colormap +Set2: colors.Colormap +Set3: colors.Colormap +tab10: colors.Colormap +tab20: colors.Colormap +tab20b: colors.Colormap +tab20c: colors.Colormap +grey: colors.Colormap +gist_grey: colors.Colormap +gist_yerg: colors.Colormap +Grays: colors.Colormap +# Reversed colormaps +magma_r: colors.Colormap +inferno_r: colors.Colormap +plasma_r: colors.Colormap +viridis_r: colors.Colormap +cividis_r: colors.Colormap +twilight_r: colors.Colormap +twilight_shifted_r: colors.Colormap +turbo_r: colors.Colormap +berlin_r: colors.Colormap +managua_r: colors.Colormap +vanimo_r: colors.Colormap +Blues_r: colors.Colormap +BrBG_r: colors.Colormap +BuGn_r: colors.Colormap +BuPu_r: colors.Colormap +CMRmap_r: colors.Colormap +GnBu_r: colors.Colormap +Greens_r: colors.Colormap +Greys_r: colors.Colormap +OrRd_r: colors.Colormap +Oranges_r: colors.Colormap +PRGn_r: colors.Colormap +PiYG_r: colors.Colormap +PuBu_r: colors.Colormap +PuBuGn_r: colors.Colormap +PuOr_r: colors.Colormap +PuRd_r: colors.Colormap +Purples_r: colors.Colormap +RdBu_r: colors.Colormap +RdGy_r: colors.Colormap +RdPu_r: colors.Colormap +RdYlBu_r: colors.Colormap +RdYlGn_r: colors.Colormap +Reds_r: colors.Colormap +Spectral_r: colors.Colormap +Wistia_r: colors.Colormap +YlGn_r: colors.Colormap +YlGnBu_r: colors.Colormap +YlOrBr_r: colors.Colormap +YlOrRd_r: colors.Colormap +afmhot_r: colors.Colormap +autumn_r: colors.Colormap +binary_r: colors.Colormap +bone_r: colors.Colormap +brg_r: colors.Colormap +bwr_r: colors.Colormap +cool_r: colors.Colormap +coolwarm_r: colors.Colormap +copper_r: colors.Colormap +cubehelix_r: colors.Colormap +flag_r: colors.Colormap +gist_earth_r: colors.Colormap +gist_gray_r: colors.Colormap +gist_heat_r: colors.Colormap +gist_ncar_r: colors.Colormap +gist_rainbow_r: colors.Colormap +gist_stern_r: colors.Colormap +gist_yarg_r: colors.Colormap +gnuplot_r: colors.Colormap +gnuplot2_r: colors.Colormap +gray_r: colors.Colormap +hot_r: colors.Colormap +hsv_r: colors.Colormap +jet_r: colors.Colormap +nipy_spectral_r: colors.Colormap +ocean_r: colors.Colormap +pink_r: colors.Colormap +prism_r: colors.Colormap +rainbow_r: colors.Colormap +seismic_r: colors.Colormap +spring_r: colors.Colormap +summer_r: colors.Colormap +terrain_r: colors.Colormap +winter_r: colors.Colormap +Accent_r: colors.Colormap +Dark2_r: colors.Colormap +okabe_ito_r: colors.Colormap +Paired_r: colors.Colormap +Pastel1_r: colors.Colormap +Pastel2_r: colors.Colormap +Set1_r: colors.Colormap +Set2_r: colors.Colormap +Set3_r: colors.Colormap +tab10_r: colors.Colormap +tab20_r: colors.Colormap +tab20b_r: colors.Colormap +tab20c_r: colors.Colormap +grey_r: colors.Colormap +gist_grey_r: colors.Colormap +gist_yerg_r: colors.Colormap +Grays_r: colors.Colormap diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 8bffa9c11bfe..c9e04a70b356 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -6,215 +6,327 @@ 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 - - -CIRCLE_AREA_FACTOR = 1.0 / np.sqrt(np.pi) +import numpy as np -class Collection(artist.Artist, cm.ScalarMappable): - """ - 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. +import matplotlib as mpl +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. """ - _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_separately(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 + data_trf = transform.get_affine() - transData + if not data_trf.is_affine: + paths = [data_trf.transform_path_non_affine(p) for p in paths] + return mpath.get_path_collection_extents( + data_trf.get_affine(), 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(): @@ -224,33 +336,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 @@ -258,7 +365,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) @@ -266,6 +373,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()) @@ -285,45 +393,134 @@ def draw(self, renderer): 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) + combined_transform = transforms.Affine2D(trans[0]) + transform else: combined_transform = transform extents = paths[0].get_extents(combined_transform) - width, height = renderer.get_canvas_width_height() - if (extents.width < width and - extents.height < height): + 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_foreground(tuple(edgecolors[0]), isRGBA=True) 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]) renderer.draw_markers( gc, paths[0], combined_transform.frozen(), - mpath.Path(offsets), transOffset, tuple(facecolors[0])) + 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 @@ -332,50 +529,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:: @@ -395,337 +597,484 @@ 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_linestyle(self, ls): + """ + Set the linestyle(s) for the collection. + + Parameters + ---------- + ls : {'-', '--', '-.', ':', '', ...} or (offset, on-off-seq) or list thereof + If a list, the individual elements are assigned to the elements of the + collection. + + 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 + ======================================================= ================ + + - A tuple describing the start position and lengths of dashes and spaces: + + (offset, onoffseq) + + where + + - *offset* is a float specifying the offset (in points); i.e. how much + is the dash pattern shifted. + - *onoffseq* is a sequence of on and off ink in points. There can be + arbitrary many pairs of on and off values. + + Example: The tuple ``(0, (10, 5, 1, 5))`` means that the pattern starts + at the beginning of the line. It draws a 10 point long dash, + then a 5 point long space, then a 1 point long dash, followed by a 5 point + long space, and then the pattern repeats. + + For examples see :doc:`/gallery/lines_bars_and_markers/linestyles`. + """ + # get the list of raw 'unscaled' dash patterns + self._us_linestyles = mlines._get_dash_patterns(ls) + + # broadcast and scale the lw and dash patterns + self._linewidths, self._linestyles = self._bcast_lwls( + self._us_lw, self._us_linestyles) - def set_offset_position(self, offset_position): + @_docstring.interpd + def set_capstyle(self, cs): """ - 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 `.CapStyle` for the collection (for all its elements). + + Parameters + ---------- + cs : `.CapStyle` or %(CapStyle)s """ - if offset_position not in ('screen', 'data'): - raise ValueError("offset_position must be 'screen' or 'data'") - self._offset_position = offset_position + self._capstyle = CapStyle(cs) - def get_offset_position(self): + @_docstring.interpd + def get_capstyle(self): """ - 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. + Return the cap style for the collection (for all its elements). + + Returns + ------- + %(CapStyle)s or None """ - return self._offset_position + return self._capstyle.name if self._capstyle else None - def set_linewidth(self, lw): + @_docstring.interpd + def set_joinstyle(self, js): """ - 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 + Set the `.JoinStyle` for the collection (for all its elements). - ACCEPTS: float or sequence of floats + Parameters + ---------- + js : `.JoinStyle` or %(JoinStyle)s """ - if lw is None: - lw = mpl.rcParams['patch.linewidth'] - self._linewidths = self._get_value(lw) + self._joinstyle = JoinStyle(js) - def set_linewidths(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_lw(self, lw): - """alias for set_linewidth""" - return self.set_linewidth(lw) + Returns + ------- + %(JoinStyle)s or None + """ + return self._joinstyle.name if self._joinstyle else None - def set_linestyle(self, ls): + @staticmethod + def _bcast_lwls(linewidths, dashes): """ - Set the linestyle(s) for the collection. + 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. - ACCEPTS: ['solid' | 'dashed', 'dashdot', 'dotted' | - (offset, on-off-dash-seq) ] + Parameters + ---------- + linewidths : list + line widths of collection + dashes : list + dash specification (offset, (dash pattern tuple)) + + Returns + ------- + linewidths, dashes : list + Will be the same length, dashes are scaled by paired linewidth """ - 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 + 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) + + # scale the dash patterns + dashes = [mlines._scale_dashes(o, d, lw) + for (o, d), lw in zip(dashes, linewidths)] - def set_linestyles(self, ls): - """alias for set_linestyle""" - return self.set_linestyle(ls) + return linewidths, dashes - def set_dashes(self, ls): - """alias for set_linestyle""" - return self.set_linestyle(ls) + 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 spec (all patches have same color), or a - sequence of specs; 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 spec or sequence of specs + 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 spec (all patches have same color), or a - sequence of specs; 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 spec or sequence of specs - """ - 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: - return - if self._A.ndim > 1: - raise ValueError('Collections can only map rank 1 arrays') - if not self.check_update("array"): + if not self._set_mappable_flags(): 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): @@ -736,12 +1085,11 @@ class _CollectionWithSizes(Collection): 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 @@ -752,12 +1100,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([]) @@ -769,179 +1116,562 @@ def set_sizes(self, sizes, dpi=72.0): 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. - *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. + This is useful for obtaining a legend for a `~.Axes.scatter` plot; + e.g.:: - *closed*, when *True*, will explicitly close the polygon. + scatter = plt.scatter([1, 2, 3], [4, 5, 6], c=[7, 2, 3], num=None) + plt.legend(*scatter.legend_elements()) - %(Collection)s + 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} + + # Pre-format all labels + # TODO: check whether we can switch to + # formatted_labels = fmt.format_ticks(label_values) + # There are subtle differences for some formatters as that passes the + # indices to __call__ as well. + fmt.set_locs(label_values) + formatted_labels = [fmt(lab) for lab in label_values] + + for val, formatted in zip(values, formatted_labels): + 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) + labels.append(formatted) + + return handles, labels + + +class PolyCollection(_CollectionWithSizes): + + 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): + """ + 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) + + @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) + + @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): """ - *xranges* - sequence of (*xmin*, *xwidth*) + Set new values for the two bounding curves. - *yrange* - *ymin*, *ywidth* + Parameters + ---------- + t : array-like + The ``self.t_direction`` coordinates of the nodes defining the curves. - %(Collection)s + 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 """ - 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) + t, f1, f2 = self.axes._fill_between_process_units( + self.t_direction, self._f_direction, t, f1, f2) - @staticmethod - def span_where(x, ymin, ymax, where, **kwargs): + 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() + t_where = t.data[where] if np.ma.isMA(t) else t[where] + f1_where = f1.data[where] if np.ma.isMA(f1) else f1[where] + f2_where = f2.data[where] if np.ma.isMA(f2) else f2[where] + n = len(t_where) + if n > 0: + pts = np.empty((2 * n, 2)) # Preallocate and fill for speed + pts[:n, 0], pts[:n, 1] = t_where, f1_where + pts[n:, 0], pts[n:, 1] = t_where, f2_where + self._bbox.update_from_data_xy(self._fix_pts_xy_order(pts)) + + 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] + + # Build polygon: start -> along f1 -> end -> back along f2 (reversed) + # Preallocate and fill for speed + n = len(t_slice) + pts = np.empty((2 * n + 2, 2)) + pts[0, :] = start + pts[1:n+1, 0], pts[1:n+1, 1] = t_slice, f1_slice + pts[n+1, :] = end + pts[n+2:, 0], pts[n+2:, 1] = t_slice[::-1], f2_slice[::-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*.""" - _path_generator = mpath.Path.unit_regular_polygon + """A collection of n-sided regular polygons.""" - _factor = CIRCLE_AREA_FACTOR + _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)] @@ -954,208 +1684,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) + 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, @@ -1165,125 +1915,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 @@ -1293,57 +1993,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.getitem_checked( + {"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() @@ -1356,15 +2047,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() @@ -1377,92 +2064,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. - """ - _factor = CIRCLE_AREA_FACTOR + """A collection of circles, drawn using splines.""" + + _factor = np.pi ** (-1/2) - @docstring.dedent_interpd 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'] + """A collection of ellipses, drawn using splines.""" - 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. - - 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 @@ -1481,7 +2151,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 @@ -1500,43 +2170,75 @@ def _set_transforms(self): 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: @@ -1551,7 +2253,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) @@ -1563,17 +2265,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() @@ -1594,31 +2293,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] @@ -1631,100 +2326,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. - 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' + Parameters + ---------- + coordinates : (M+1, N+1, 2) array-like + The vertices. ``coordinates[m, n]`` specifies the (x, y) coordinates + of vertex (m, n). + + 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_datalim(self, transData): - return (self.get_transform() - transData).transform_bbox(self._bbox) + 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 @@ -1734,89 +2453,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). + + antialiased : bool, default: True - 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)) + shading : {'flat', 'gouraud'}, default: 'flat' - return triangles, colors + 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. - @allow_rasterization + """ + + 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 c4caae295681..100807dd7f18 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1,822 +1,1220 @@ -''' -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 functools +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 + + +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 + + 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 - 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:: + def get_subplotspec(self): + # make tight_layout happy.. + return ( + self._cbar.ax.get_subplotspec() + or getattr(self._orig_locator, "get_subplotspec", lambda: None)()) - colors.Normalize(clip=False) - To show the colors versus index instead of on the 0-1 scale, - use:: +def _remove_cbar_axes(ax, cbar): + """ + Replacement remove method for a colorbar's axes, so that the colorbar is + properly removed. - norm=colors.NoNorm. + Note we define this at the module level to preserve pickling. A lambda or + local def within the Colorbar.__init__ method will not work. + """ + cbar.remove() - 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.getitem_checked( + {'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, autolim=False) + + 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) + + # Ensure proper cleanup when `cbar.ax.remove()` is called. We ensure + # this by overriding the Axes' remove method, so that `cbar.ax.remove()` + # actually calls `cbar.remove()`. In turn, we store the original Axes' + # remove method in `_ax_remove`, which `cbar.remove()` will eventually + # call to clean up the Axes itself. + self._ax_remove = self.ax._remove_method + self.ax._remove_method = functools.partial(_remove_cbar_axes, cbar=self) + + @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) + # rectangle: + xyout = np.array([[0, 0], [0, bot], [1, bot], [1, 0], + [1, 1], [1, top], [0, top], [0, 1], + [0, 0]]) - self.update_ticks() - - 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) - self.ax.add_collection(col) - - 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] + + # 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, autolim=False) + self.stale = True + + 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()) - if isinstance(locator, ticker.LogLocator): - eps = 1e-10 - b = b[(b <= intv[1] * (1 + eps)) & (b >= intv[0] * (1 - eps))] + 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: - eps = (intv[1] - intv[0]) * 1e-10 - b = b[(b <= intv[1] + eps) & (b >= intv[0] - eps)] - ticks = self._locate(b) - 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) + 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.ax) + + 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 @@ -826,274 +1224,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.getitem_checked({ + "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.getitem_checked( + {None: None, "left": "vertical", "right": "vertical", + "top": "horizontal", "bottom": "horizontal"}, location=location) + + +def _get_ticklocation_from_orientation(orientation): + return _api.getitem_checked( + {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'): @@ -1114,214 +1463,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: + a._colorbars.append(cax) # tell the parent it has a colorbar + 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] - - 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]]]) - - 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 + loc_settings = _normalize_location_orientation(location, orientation) + kwargs['orientation'] = loc_settings['orientation'] + location = kwargs['ticklocation'] = loc_settings['location'] - 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) + 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) - 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="") + parent._colorbars.append(cax) # tell the parent it has a colorbar + 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..095b93ccfe85 --- /dev/null +++ b/lib/matplotlib/colorizer.py @@ -0,0 +1,907 @@ +""" +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, artist, scale +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 " + "as arguments to the norm object 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): + norm = _ensure_norm(norm, n_components=self.cmap.n_variates) + 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 + """ + in_init = self._cmap is None + cmap_obj = _ensure_cmap(cmap, accept_multivariate=True) + if not in_init and self.norm.n_components != cmap_obj.n_variates: + raise ValueError(f"The colormap {cmap} does not support " + f"{self.norm.n_components} variates as required by " + f"the {type(self.norm)} on this Colorizer") + self._cmap = cmap_obj + 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. + + For scalar data, the limits may also be passed as a + tuple (*vmin*, *vmax*) single positional argument. + + .. ACCEPTS: (vmin: float, vmax: float) + """ + if self.norm.n_components == 1: + 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'): + # Since the @vmin/vmax.setter invokes colors._sanitize_extrema() + # to sanitize the input, the input is not sanitized here + if vmin is not None: + self.norm.vmin = vmin + if vmax is not None: + self.norm.vmax = 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. + if np.ma.getmask(data) or data is None: + # NOTE: for multivariate data, if *any* of the fields are masked, + # "[]" is returned here + return "[]" + + if isinstance(self.norm, colors.MultiNorm): + norms = self.norm.norms + if isinstance(self.cmap, colors.BivarColormap): + n_s = (self.cmap.N, self.cmap.M) + else: # colors.MultivarColormap + n_s = [part.N for part in self.cmap] + else: # colors.Colormap + norms = [self.norm] + data = [data] + n_s = [self.cmap.N] + + os = [f"{d:-#.{self._sig_digits_from_norm(no, d, n)}g}" + for no, d, n in zip(norms, data, n_s)] + return f"[{', '.join(os)}]" + + @staticmethod + def _sig_digits_from_norm(norm, data, n): + # Determines the number of significant digits + # to use for a number given a norm, and n, where n is the + # number of colors in the colormap. + normed = norm(data) + if np.isfinite(normed): + if isinstance(norm, colors.BoundaryNorm): + # not an invertible normalization mapping + cur_idx = np.argmin(np.abs(norm.boundaries - data)) + neigh_idx = max(0, cur_idx - 1) + # use max diff to prevent delta == 0 + delta = np.diff(norm.boundaries[neigh_idx:cur_idx + 2]).max() + elif norm.vmin == norm.vmax: + # singular norms, use delta of 10% of only value + delta = np.abs(norm.vmin * .1) + else: + # Midpoints of neighboring color intervals. + neighbors = 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 g_sig_digits + + +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 = _ensure_multivariate_data(A, self.norm.n_components) + + A = cbook.safe_masked_invalid(A, copy=True) + if not np.can_cast(A.dtype, float, "same_kind"): + if A.dtype.fields is None: + + raise TypeError(f"Image data of dtype {A.dtype} cannot be " + f"converted to float") + else: + for key in A.dtype.fields: + if not np.can_cast(A[key].dtype, float, "same_kind"): + raise TypeError(f"Image data of dtype {A.dtype} cannot be " + f"converted to a sequence of floats") + 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.""", + multi_cmap_doc="""\ +cmap : str, `~matplotlib.colors.Colormap`, `~matplotlib.colors.BivarColormap`\ + or `~matplotlib.colors.MultivarColormap`, default: :rc:`image.cmap` + The Colormap instance or registered colormap name used to map + data values to colors. + + Multivariate data is only accepted if a multivariate colormap + (`~matplotlib.colors.BivarColormap` or `~matplotlib.colors.MultivarColormap`) + is used.""", + 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.""", + multi_norm_doc="""\ +norm : str, `~matplotlib.colors.Normalize` or list, optional + The normalization method used to scale 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. + 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 this case, a suitable `.Normalize` subclass is dynamically generated + and instantiated. + - A list of scale names or `.Normalize` objects matching the number of + variates in the colormap, for use with `~matplotlib.colors.BivarColormap` + or `~matplotlib.colors.MultivarColormap`, i.e. ``["linear", "log"]``.""", + 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).""", + multi_vmin_vmax_doc="""\ +vmin, vmax : float or list, 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). + + A list of values (vmin or vmax) can be used to define independent limits + for each variate when using a `~matplotlib.colors.BivarColormap` or + `~matplotlib.colors.MultivarColormap`.""", +) + + +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) + + +def _ensure_norm(norm, n_components=1): + if n_components == 1: + _api.check_isinstance((colors.Norm, str, None), norm=norm) + if norm is None: + norm = colors.Normalize() + elif isinstance(norm, str): + scale_cls = _api.getitem_checked(scale._scale_mapping, norm=norm) + return _auto_norm_from_scale(scale_cls)() + return norm + elif n_components > 1: + if not np.iterable(norm): + _api.check_isinstance((colors.MultiNorm, None, tuple), norm=norm) + if norm is None: + norm = colors.MultiNorm(['linear']*n_components) + else: # iterable, i.e. multiple strings or Normalize objects + norm = colors.MultiNorm(norm) + if isinstance(norm, colors.MultiNorm) and norm.n_components == n_components: + return norm + raise ValueError( + f"Invalid norm for multivariate colormap with {n_components} inputs") + else: # n_components == 0 + raise ValueError( + "Invalid cmap. A colorizer object must have a cmap with `n_variates` >= 1") + + +def _ensure_cmap(cmap, accept_multivariate=False): + """ + Ensure that we have a `.Colormap` object. + + For internal use to preserve type stability of errors. + + Parameters + ---------- + cmap : None, str, Colormap + + - if a `~matplotlib.colors.Colormap`, + `~matplotlib.colors.MultivarColormap` or + `~matplotlib.colors.BivarColormap`, + return it + - if a string, look it up in three corresponding databases + when not found: raise an error based on the expected shape + - if None, look up the default color map in mpl.colormaps + accept_multivariate : bool, default False + - if False, accept only Colormap, string in mpl.colormaps or None + + Returns + ------- + Colormap + + """ + if accept_multivariate: + types = (colors.Colormap, colors.BivarColormap, colors.MultivarColormap) + mappings = (mpl.colormaps, mpl.multivar_colormaps, mpl.bivar_colormaps) + else: + types = (colors.Colormap, ) + mappings = (mpl.colormaps, ) + + if isinstance(cmap, types): + return cmap + + cmap_name = mpl._val_or_rc(cmap, "image.cmap") + + for mapping in mappings: + if cmap_name in mapping: + return mapping[cmap_name] + + # this error message is a variant of _api.check_in_list but gives + # additional hints as to how to access multivariate colormaps + + raise ValueError(_api.list_suggestion_error_msg('cmap', cmap, mpl.colormaps) + + "\nSee `matplotlib.bivar_colormaps()` and" + " `matplotlib.multivar_colormaps()` for" + " bivariate and multivariate colormaps") + + +def _ensure_multivariate_data(data, n_components): + """ + Ensure that the data has dtype with n_components. + Input data of shape (n_components, n, m) is converted to an array of shape + (n, m) with data type np.dtype(f'{data.dtype}, ' * n_components) + Complex data is returned as a view with dtype np.dtype('float64, float64') + or np.dtype('float32, float32') + If n_components is 1 and data is not of type np.ndarray (i.e. PIL.Image), + the data is returned unchanged. + If data is None, the function returns None + + Parameters + ---------- + n_components : int + Number of variates in the data. + data : np.ndarray, PIL.Image or None + + Returns + ------- + np.ndarray, PIL.Image or None + """ + + if isinstance(data, np.ndarray): + if len(data.dtype.descr) == n_components: + # pass scalar data + # and already formatted data + return data + elif data.dtype in [np.complex64, np.complex128]: + if n_components != 2: + raise ValueError("Invalid data entry for multivariate data. " + "Complex numbers are incompatible with " + f"{n_components} variates.") + + # pass complex data + if data.dtype == np.complex128: + dt = np.dtype('float64, float64') + else: + dt = np.dtype('float32, float32') + + reconstructed = np.ma.array(np.ma.getdata(data).view(dt)) + if np.ma.is_masked(data): + for descriptor in dt.descr: + reconstructed[descriptor[0]][data.mask] = np.ma.masked + return reconstructed + + if n_components > 1 and len(data) == n_components: + # convert data from shape (n_components, n, m) + # to (n, m) with a new dtype + data = [np.ma.array(part, copy=False) for part in data] + dt = np.dtype(', '.join([f'{part.dtype}' for part in data])) + fields = [descriptor[0] for descriptor in dt.descr] + reconstructed = np.ma.empty(data[0].shape, dtype=dt) + for i, f in enumerate(fields): + if data[i].shape != reconstructed.shape: + raise ValueError("For multivariate data all variates must have same " + f"shape, not {data[0].shape} and {data[i].shape}") + reconstructed[f] = data[i] + if np.ma.is_masked(data[i]): + reconstructed[f][data[i].mask] = np.ma.masked + return reconstructed + + if n_components == 1: + # PIL.Image gets passed here + return data + + elif n_components == 2: + raise ValueError("Invalid data entry for multivariate data. The data" + " must contain complex numbers, or have a first dimension 2," + " or be of a dtype with 2 fields") + else: + raise ValueError("Invalid data entry for multivariate data. The shape" + f" of the data must have a first dimension {n_components}" + f" or be of a dtype with {n_components} fields") diff --git a/lib/matplotlib/colorizer.pyi b/lib/matplotlib/colorizer.pyi new file mode 100644 index 000000000000..9a5a73415d83 --- /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.Norm | None = ..., + ) -> None: ... + @property + def norm(self) -> colors.Norm: ... + @norm.setter + def norm(self, norm: colors.Norm | 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.Norm: ... + @norm.setter + def norm(self, norm: colors.Norm | str | None) -> None: ... + def set_norm(self, norm: colors.Norm | str | None) -> None: ... + def autoscale(self) -> None: ... + def autoscale_None(self) -> None: ... + + +class _ScalarMappable(_ColorizerInterface): + def __init__( + self, + norm: colors.Norm | 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 772da0f414c4..685a96cc7803 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -1,464 +1,678 @@ """ -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 +from abc import ABC, abstractmethod +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 +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 - Caching is used for more efficient conversion upon repeated calls - with the same argument. - Ordinarily only the single instance instantiated in this module, - *colorConverter*, is needed. - """ - 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), } +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. + + Additional color sequences can be added via + `.ColorSequenceRegistry.register`:: - cache = {} + mpl.color_sequences.register('rgb', ['r', 'g', 'b']) + """ - def to_rgb(self, arg): + _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, + 'okabe_ito': _cm._okabe_ito_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): + return list(_api.getitem_checked(self._color_sequences, _error_cls=KeyError, + sequence_name=item)) + + def __iter__(self): + return iter(self._color_sequences) + + def __len__(self): + return len(self._color_sequences) + + 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. + + *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() - Special case to handle "no color": if *c* is "none" (case-insensitive), - then an empty array will be returned. Same for an empty list. - """ + +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 #: :meta private: +hexColorPattern = re.compile(r"\A#[a-fA-F0-9]{6}\Z") #: :meta private: +rgb2hex = to_hex #: :meta private: +hex2color = to_rgb #: :meta private: + + +class ColorConverter: + """ + A class only kept for backwards compatibility. + + Its functionality is entirely provided by module-level functions. + + :meta private: + """ + 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 or 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,179 +680,271 @@ 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] - - distance = (xind[1:-1] - x[ind - 1]) / (x[ind] - x[ind - 1]) - lut[1:-1] = distance * (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 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() + self._ensure_inited() + 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) - 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 + self._ensure_inited() + other._ensure_inited() + return np.array_equal(self._lut, other._lut) + + def get_bad(self): + """Get the color for masked values.""" + self._ensure_inited() + return np.array(self._lut[self._i_bad]) + + @_api.deprecated( + "3.11", + pending=True, + alternative="cmap.with_extremes(bad=...) or Colormap(bad=...)") def set_bad(self, color='k', alpha=None): - """Set color to be used for masked values. + """Set the color for masked values.""" + self._set_extremes(bad=(color, alpha)) + + def get_under(self): + """Get the color for low out-of-range values.""" + self._ensure_inited() + return np.array(self._lut[self._i_under]) + + @_api.deprecated( + "3.11", + pending=True, + alternative="cmap.with_extremes(under=...) or Colormap(under=...)") + def set_under(self, color='k', alpha=None): + """Set the color for low out-of-range values.""" + self._set_extremes(under=(color, alpha)) + + def get_over(self): + """Get the color for high out-of-range values.""" + self._ensure_inited() + return np.array(self._lut[self._i_over]) + + @_api.deprecated( + "3.11", + pending=True, + alternative="cmap.with_extremes(over=...) or Colormap(over=...)") + def set_over(self, color='k', alpha=None): + """Set the color for high out-of-range values.""" + self._set_extremes(over=(color, alpha)) + + @_api.deprecated( + "3.11", + pending=True, + alternative="cmap.with_extremes(bad=..., under=..., over=...) or " + "Colormap(bad=..., under=..., over=...)") + def set_extremes(self, *, bad=None, under=None, over=None): """ - self._rgba_bad = colorConverter.to_rgba(color, alpha) - if self._isinit: - self._set_extremes() + Set the colors for masked (*bad*) values and, when ``norm.clip = + False``, low (*under*) and high (*over*) out-of-range values. + """ + self._set_extremes(bad=bad, under=under, over=over) - def set_under(self, color='k', alpha=None): - """Set color to be used for low out-of-range values. - Requires norm.clip = False + def with_extremes(self, *, bad=None, under=None, over=None): """ - self._rgba_under = colorConverter.to_rgba(color, alpha) - if self._isinit: - self._set_extremes() + 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_over(self, color='k', alpha=None): - """Set color to be used for high out-of-range values. - Requires norm.clip = False + def _set_extremes(self, bad=None, under=None, over=None): """ - self._rgba_over = colorConverter.to_rgba(color, alpha) + Set the colors for masked (*bad*) and out-of-range (*under* and *over*) values. + + Parameters that are None are left unchanged. + """ + if bad is not None: + self._rgba_bad = to_rgba(bad) + if under is not None: + self._rgba_under = to_rgba(under) + if over is not None: + self._rgba_over = to_rgba(over) if self._isinit: - self._set_extremes() + self._update_lut_extremes() - def _set_extremes(self): + def _update_lut_extremes(self): + """Ensure than an existing lookup table has the correct extreme values.""" if self._rgba_under: self._lut[self._i_under] = self._rgba_under else: @@ -649,221 +955,1535 @@ 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: + raise ValueError("'alpha' must be between 0 and 1, inclusive") + new_cm = self.copy() + new_cm._ensure_inited() + 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): + def _ensure_inited(self): if not self._isinit: self._init() - return (np.alltrue(self._lut[:, 0] == self._lut[:, 1]) and - np.alltrue(self._lut[:, 0] == self._lut[:, 2])) + + def is_gray(self): + """Return whether the colormap is grayscale.""" + self._ensure_inited() + 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( + # Assemble the LUT first in a local variable in case of parallel threads + lut = np.ones((self.N + 3, 4), float) + lut[:-3, 0] = _create_lookup_table( self.N, self._segmentdata['red'], self._gamma) - self._lut[:-3, 1] = makeMappingArray( + lut[:-3, 1] = _create_lookup_table( self.N, self._segmentdata['green'], self._gamma) - self._lut[:-3, 2] = makeMappingArray( + lut[:-3, 2] = _create_lookup_table( self.N, self._segmentdata['blue'], self._gamma) if 'alpha' in self._segmentdata: - self._lut[:-3, 3] = makeMappingArray( + lut[:-3, 3] = _create_lookup_table( self.N, self._segmentdata['alpha'], 1) + self._lut = lut self._isinit = True - self._set_extremes() + self._update_lut_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. - 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. + .. 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='unnamed', 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 + # Assemble the LUT first in a local variable in case of parallel threads + lut = np.zeros((self.N + 3, 4), float) + lut[:-3] = to_rgba_array(self.colors) + self._lut = lut self._isinit = True - self._set_extremes() + self._update_lut_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. + self._ensure_inited() + 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 Normalize(object): +class MultivarColormap: """ - A class which, when called, can normalize data into - the ``[0.0, 1.0]`` interval. + 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 + + 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): + # in-place change is ok, since we've just created c as a copy + c._set_extremes(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): + # in-place change is ok, since we've just created c as a copy + c._set_extremes(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: """ - def __init__(self, vmin=None, vmax=None, clip=False): + 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 *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:: - vmin==vmax + 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 - 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*. + @property + def lut(self): """ - self.vmin = vmin - self.vmax = vmax - self.clip = clip + 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() + extremes = ( + dict(bad=self._rgba_bad, over=self._rgba_outside, under=self._rgba_outside) + if self.shape in ['ignore', 'circleignore'] + else dict(bad=self._rgba_bad) + ) + 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', **extremes) + + 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', **extremes) + else: + raise KeyError(f"only 0 or 1 are" + f" valid keys for BivarColormap, not {item!r}") + 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): + # Perform bilinear interpolation + + s = self.patch.shape + + # Indices (whole and fraction) of the new grid points + row = np.linspace(0, s[0] - 1, self.N)[:, np.newaxis] + col = np.linspace(0, s[1] - 1, self.N)[np.newaxis, :] + left = row.astype(int) # floor not needed because all values are nonnegative + top = col.astype(int) # floor not needed because all values are nonnegative + row_frac = (row - left)[:, :, np.newaxis] + col_frac = (col - top)[:, :, np.newaxis] + + # Indices of the next edges, clipping where needed + right = np.clip(left + 1, 0, s[0] - 1) + bottom = np.clip(top + 1, 0, s[1] - 1) + + # Values at the corners + tl = self.patch[left, top, :] + tr = self.patch[right, top, :] + bl = self.patch[left, bottom, :] + br = self.patch[right, bottom, :] + + # Interpolate between the corners + lut = (tl * (1 - row_frac) * (1 - col_frac) + + tr * row_frac * (1 - col_frac) + + bl * (1 - row_frac) * col_frac + + br * row_frac * col_frac) + + # Add the alpha channel + self._lut = np.concatenate([lut, np.ones((self.N, self.N, 1))], axis=2) + + 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 Norm(ABC): + """ + Abstract base class for normalizations. + + Subclasses include `Normalize` which maps from a scalar to + a scalar. However, this class makes no such requirement, and subclasses may + support the normalization of multiple variates simultaneously, with + separate normalization for each variate. + """ + + def __init__(self): + self.callbacks = cbook.CallbackRegistry(signals=["changed"]) + + @property + @abstractmethod + def vmin(self): + """Lower limit of the input data interval; maps to 0.""" + pass + + @property + @abstractmethod + def vmax(self): + """Upper limit of the input data interval; maps to 1.""" + pass + + @property + @abstractmethod + def clip(self): + """ + Determines the behavior for mapping values outside the range ``[vmin, vmax]``. + + See the *clip* parameter in `.Normalize`. + """ + pass + + @abstractmethod + def __call__(self, value, clip=None): + """ + 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)``. + """ + pass + + @abstractmethod + def autoscale(self, A): + """Set *vmin*, *vmax* to min, max of *A*.""" + pass + + @abstractmethod + def autoscale_None(self, A): + """If *vmin* or *vmax* are not set, use the min/max of *A* to set them.""" + pass + + @abstractmethod + def scaled(self): + """Return whether *vmin* and *vmax* are both set.""" + pass + + def _changed(self): + """ + Call this whenever the norm is changed to notify all the + callback listeners to the 'changed' signal. + """ + self.callbacks.process('changed') + + @property + @abstractmethod + def n_components(self): + """ + The number of normalized components. + + This is the number of elements of the parameter to ``__call__`` and of + *vmin*, *vmax*. + """ + pass + + +class Normalize(Norm): + """ + 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): + """ + 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. + """ + super().__init__() + self._vmin = _sanitize_extrema(vmin) + self._vmax = _sanitize_extrema(vmax) + self._clip = clip + self._scale = None + + @property + def vmin(self): + # docstring inherited + 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): + # docstring inherited + 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): + # docstring inherited + return self._clip + + @clip.setter + def clip(self, value): + if value != self._clip: + self._clip = value + self._changed() @staticmethod def process_value(value): @@ -872,57 +2492,60 @@ 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)*. - """ + # docstring inherited 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 @@ -933,107 +2556,493 @@ 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): + # docstring inherited + 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): + # docstring inherited + 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): + # docstring inherited + return self.vmin is not None and self.vmax is not None + + @property + def n_components(self): + """ + The number of distinct components supported (1). + + This is the number of elements of the parameter to ``__call__`` and of + *vmin*, *vmax*. + + This class support only a single component, as opposed to `MultiNorm` + which supports multiple components. """ - Set *vmin*, *vmax* to min, max of *A*. + return 1 + + +class TwoSlopeNorm(Normalize): + def __init__(self, vcenter, vmin=None, vmax=None): """ - self.vmin = ma.min(A) - self.vmax = ma.max(A) + Normalize data with a set center. + + 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. + + 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]) + """ + + 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): - ' 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) + """ + 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 = np.atleast_1d(result)[0] + return result + + def inverse(self, value): + if not self.scaled(): + 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 - def scaled(self): - 'return true if vmin and vmax set' - return (self.vmin is not None and self.vmax is not None) +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 -class LogNorm(Normalize): + def autoscale(self, A): + """ + Set *halfrange* to ``max(abs(A-vcenter))``, then set *vmin* and *vmax*. + """ + A = np.asanyarray(A) + self.halfrange = max(self._vcenter-A.min(), + A.max()-self._vcenter) + + def autoscale_None(self, 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): """ - Normalize a given value to the 0-1 range on a log scale + 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. """ - def __call__(self, value, clip=None): - if clip is None: - clip = self.clip - result, is_scalar = self.process_value(value) + if base_norm_cls is None: + return functools.partial(make_norm_from_scale, scale_cls, init=init) - result = ma.masked_less_equal(result, 0, copy=False) + 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 = () - 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 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 ScaleNorm(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: - 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) - if is_scalar: - result = result[0] - return result + 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: + ScaleNorm.__name__ = f"{scale_cls.__name__}Norm" + ScaleNorm.__qualname__ = f"{scale_cls.__qualname__}Norm" + else: + ScaleNorm.__name__ = base_norm_cls.__name__ + ScaleNorm.__qualname__ = base_norm_cls.__qualname__ + ScaleNorm.__module__ = base_norm_cls.__module__ + ScaleNorm.__doc__ = base_norm_cls.__doc__ + + return ScaleNorm + + +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. - def inverse(self, value): - if not self.scaled(): - raise ValueError("Not invertible until scaled") - vmin, vmax = self.vmin, self.vmax + Parameters + ---------- + functions : (callable, callable) + two-tuple of the forward and inverse functions for the normalization. + The forward function must be monotonic. - if cbook.iterable(value): - val = ma.asarray(value) - return vmin * ma.power((vmax / vmin), val) - else: - return vmin * pow((vmax / vmin), value) + Both functions must have the signature :: - def autoscale(self, A): - """ - Set *vmin*, *vmax* to min, max of *A*. - """ - A = ma.masked_less_equal(A, 0, copy=False) - self.vmin = ma.min(A) - self.vmax = ma.max(A) + 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. + """ - 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) +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 @@ -1043,118 +3052,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): @@ -1171,18 +3163,16 @@ def __call__(self, value, clip=None): elif vmin == vmax: result.fill(0) else: - res_mask = result.data < 0 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) 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[res_mask] = 0 if is_scalar: result = result[0] return result @@ -1190,125 +3180,464 @@ 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(val, 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:: + # 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. - b[i] <= v < b[i+1] - - 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 +class MultiNorm(Norm): + """ + A class which contains multiple scalar norms. + """ + + def __init__(self, norms, vmin=None, vmax=None, clip=None): + """ + Parameters + ---------- + norms : list of (str or `Normalize`) + The constituent norms. The list must have a minimum length of 1. + vmin, vmax : None or list of (float or None) + Limits of the constituent norms. + If a list, one value is assigned to each of the constituent + norms. + If None, the limits of the constituent norms + are not changed. + clip : None or list of bools, default: None + Determines the behavior for mapping values outside the range + ``[vmin, vmax]`` for the constituent norms. + If a list, each value is assigned to each of the constituent + norms. + If None, the behaviour of the constituent norms is not changed. + """ + if cbook.is_scalar_or_string(norms): + raise ValueError( + "MultiNorm must be assigned an iterable of norms, where each " + f"norm is of type `str`, or `Normalize`, not {type(norms)}") + + if len(norms) < 1: + raise ValueError("MultiNorm must be assigned at least one norm") + + def resolve(norm): + if isinstance(norm, str): + scale_cls = _api.getitem_checked(scale._scale_mapping, norm=norm) + return mpl.colorizer._auto_norm_from_scale(scale_cls)() + elif isinstance(norm, Normalize): + return norm + else: + raise ValueError( + "Each norm assigned to MultiNorm must be " + f"of type `str`, or `Normalize`, not {type(norm)}") + + self._norms = tuple(resolve(norm) for norm in norms) + + self.callbacks = cbook.CallbackRegistry(signals=["changed"]) + + self.vmin = vmin + self.vmax = vmax + self.clip = clip + + for n in self._norms: + n.callbacks.connect('changed', self._changed) + + @property + def n_components(self): + """Number of norms held by this `MultiNorm`.""" + return len(self._norms) + + @property + def norms(self): + """The individual norms held by this `MultiNorm`.""" + return self._norms + + @property + def vmin(self): + """The lower limit of each constituent norm.""" + return tuple(n.vmin for n in self._norms) + + @vmin.setter + def vmin(self, values): + if values is None: + return + if not np.iterable(values) or len(values) != self.n_components: + raise ValueError("*vmin* must have one component for each norm. " + f"Expected an iterable of length {self.n_components}, " + f"but got {values!r}") + with self.callbacks.blocked(): + for norm, v in zip(self.norms, values): + norm.vmin = v + self._changed() + + @property + def vmax(self): + """The upper limit of each constituent norm.""" + return tuple(n.vmax for n in self._norms) + + @vmax.setter + def vmax(self, values): + if values is None: + return + if not np.iterable(values) or len(values) != self.n_components: + raise ValueError("*vmax* must have one component for each norm. " + f"Expected an iterable of length {self.n_components}, " + f"but got {values!r}") + with self.callbacks.blocked(): + for norm, v in zip(self.norms, values): + norm.vmax = v + self._changed() + + @property + def clip(self): + """The clip behaviour of each constituent norm.""" + return tuple(n.clip for n in self._norms) + + @clip.setter + def clip(self, values): + if values is None: + return + if not np.iterable(values) or len(values) != self.n_components: + raise ValueError("*clip* must have one component for each norm. " + f"Expected an iterable of length {self.n_components}, " + f"but got {values!r}") + with self.callbacks.blocked(): + for norm, v in zip(self.norms, values): + norm.clip = v + self._changed() + + def _changed(self): + """ + Call this whenever the norm is changed to notify all the + callback listeners to the 'changed' signal. + """ + self.callbacks.process('changed') + + def __call__(self, values, clip=None): + """ + Normalize the data and return the normalized data. + + Each component of the input is normalized via the constituent norm. + + Parameters + ---------- + values : array-like + The input data, as an iterable or a structured numpy array. + + - If iterable, must be of length `n_components`. Each element can be a + scalar or array-like and is normalized through the corresponding norm. + - If structured array, must have `n_components` fields. Each field + is normalized through the corresponding norm. + + clip : list of bools or None, optional + Determines the behavior for mapping values outside the range + ``[vmin, vmax]``. See the description of the parameter *clip* in + `.Normalize`. + If ``None``, defaults to ``self.clip`` (which defaults to + ``False``). + + Returns + ------- + tuple + Normalized input values + + Notes + ----- + If not already initialized, ``self.vmin`` and ``self.vmax`` are + initialized using ``self.autoscale_None(values)``. + """ + if clip is None: + clip = self.clip + if not np.iterable(clip) or len(clip) != self.n_components: + raise ValueError("*clip* must have one component for each norm. " + f"Expected an iterable of length {self.n_components}, " + f"but got {clip!r}") + + values = self._iterable_components_in_data(values, self.n_components) + result = tuple(n(v, clip=c) for n, v, c in zip(self.norms, values, clip)) + return result + + def inverse(self, values): + """ + Map the normalized values (i.e., index in the colormap) back to data values. + + Parameters + ---------- + values : array-like + The input data, as an iterable or a structured numpy array. + + - If iterable, must be of length `n_components`. Each element can be a + scalar or array-like and is mapped through the corresponding norm. + - If structured array, must have `n_components` fields. Each field + is mapped through the the corresponding norm. + + """ + values = self._iterable_components_in_data(values, self.n_components) + result = tuple(n.inverse(v) for n, v in zip(self.norms, values)) + return result + + def autoscale(self, A): + """ + For each constituent norm, set *vmin*, *vmax* to min, max of the corresponding + component in *A*. + + Parameters + ---------- + A : array-like + The input data, as an iterable or a structured numpy array. + + - If iterable, must be of length `n_components`. Each element + is used for the limits of one constituent norm. + - If structured array, must have `n_components` fields. Each field + is used for the limits of one constituent norm. + """ + with self.callbacks.blocked(): + A = self._iterable_components_in_data(A, self.n_components) + for n, a in zip(self.norms, A): + n.autoscale(a) + self._changed() + + def autoscale_None(self, A): + """ + If *vmin* or *vmax* are not set on any constituent norm, + use the min/max of the corresponding component in *A* to set them. + + Parameters + ---------- + A : array-like + The input data, as an iterable or a structured numpy array. + + - If iterable, must be of length `n_components`. Each element + is used for the limits of one constituent norm. + - If structured array, must have `n_components` fields. Each field + is used for the limits of one constituent norm. + """ + with self.callbacks.blocked(): + A = self._iterable_components_in_data(A, self.n_components) + for n, a in zip(self.norms, A): + n.autoscale_None(a) + self._changed() + + def scaled(self): + """Return whether both *vmin* and *vmax* are set on all constituent norms.""" + return all(n.scaled() for n in self.norms) + + @staticmethod + def _iterable_components_in_data(data, n_components): + """ + Provides an iterable over the components contained in the data. + + An input array with `n_components` fields is returned as a tuple of length n + referencing slices of the original array. + + Parameters + ---------- + data : array-like + The input data, as an iterable or a structured numpy array. + + - If iterable, must be of length `n_components` + - If structured array, must have `n_components` fields. + + Returns + ------- + tuple of np.ndarray + + """ + if isinstance(data, np.ndarray) and data.dtype.fields is not None: + # structured array + if len(data.dtype.fields) != n_components: + raise ValueError( + "Structured array inputs to MultiNorm must have the same " + "number of fields as components in the MultiNorm. Expected " + f"{n_components}, but got {len(data.dtype.fields)} fields" + ) + else: + return tuple(data[field] for field in data.dtype.names) + try: + n_elements = len(data) + except TypeError: + raise ValueError("MultiNorm expects a sequence with one element per " + f"component as input, but got {data!r} instead") + if n_elements != n_components: + if isinstance(data, np.ndarray) and data.shape[-1] == n_components: + if len(data.shape) == 2: + raise ValueError( + f"MultiNorm expects a sequence with one element per component. " + "You can use `data_transposed = data.T` " + "to convert the input data of shape " + f"{data.shape} to a compatible shape {data.shape[::-1]}") + else: + raise ValueError( + f"MultiNorm expects a sequence with one element per component. " + "You can use `data_as_list = [data[..., i] for i in " + "range(data.shape[-1])]` to convert the input data of shape " + f" {data.shape} to a compatible list") + + raise ValueError( + "MultiNorm expects a sequence with one element per component. " + f"This MultiNorm has {n_components} components, but got a sequence " + f"with {n_elements} elements" + ) + + return tuple(data[i] for i in range(n_elements)) + + 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 ---------- @@ -1317,29 +3646,39 @@ 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 + in_shape = arr.shape + # ensure numerics are done at least on float32; ints are cast as well + arr = np.asarray(arr, dtype=np.promote_types(arr.dtype, np.float32)) 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) + arr = np.expand_dims(arr, axis=0) # ensure arr is 2D 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 @@ -1357,16 +3696,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 ---------- @@ -1375,7 +3710,7 @@ def hsv_to_rgb(hsv): Returns ------- - rgb : (..., 3) ndarray + (..., 3) `~numpy.ndarray` Colors converted to RGB values in range [0, 1] """ hsv = np.asarray(hsv) @@ -1383,17 +3718,14 @@ def hsv_to_rgb(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)) - - # 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) + f"shape {hsv.shape} was found.") - # 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] @@ -1403,7 +3735,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) @@ -1444,28 +3776,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) - if in_ndim == 1: - rgb.shape = (3, ) + return rgb.reshape(in_shape) - 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): """ @@ -1475,20 +3811,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 @@ -1497,27 +3845,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 @@ -1528,29 +3886,58 @@ 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 imin, imax = intensity.min(), intensity.max() @@ -1566,11 +3953,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 @@ -1578,32 +3965,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. @@ -1611,8 +3998,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 @@ -1623,12 +4010,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() @@ -1648,18 +4036,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 @@ -1672,26 +4057,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) @@ -1708,12 +4095,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] @@ -1728,36 +4115,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: @@ -1773,69 +4162,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) @@ -1850,59 +4229,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..d7fbbf181272 --- /dev/null +++ b/lib/matplotlib/colors.pyi @@ -0,0 +1,530 @@ +from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence +from abc import ABC, abstractmethod +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 Norm(ABC): + callbacks: cbook.CallbackRegistry + def __init__(self) -> None: ... + @property + @abstractmethod + def vmin(self) -> float | tuple[float] | None: ... + @property + @abstractmethod + def vmax(self) -> float | tuple[float] | None: ... + @property + @abstractmethod + def clip(self) -> bool | tuple[bool]: ... + @abstractmethod + def __call__(self, value: np.ndarray, clip: bool | None = ...) -> ArrayLike: ... + @abstractmethod + def autoscale(self, A: ArrayLike) -> None: ... + @abstractmethod + def autoscale_None(self, A: ArrayLike) -> None: ... + @abstractmethod + def scaled(self) -> bool: ... + @abstractmethod + @property + def n_components(self) -> int: ... + + +class Normalize(Norm): + 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: ... + @property + def n_components(self) -> Literal[1]: ... + +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): ... + +class MultiNorm(Norm): + # Here "type: ignore[override]" is used for functions with a return type + # that differs from the function in the base class. + # i.e. where `MultiNorm` returns a tuple and Normalize returns a `float` etc. + def __init__( + self, + norms: ArrayLike, + vmin: ArrayLike | None = ..., + vmax: ArrayLike | None = ..., + clip: ArrayLike | None = ... + ) -> None: ... + @property + def norms(self) -> tuple[Normalize, ...]: ... + @property # type: ignore[override] + def vmin(self) -> tuple[float | None, ...]: ... + @vmin.setter + def vmin(self, values: ArrayLike | None) -> None: ... + @property # type: ignore[override] + def vmax(self) -> tuple[float | None, ...]: ... + @vmax.setter + def vmax(self, valued: ArrayLike | None) -> None: ... + @property # type: ignore[override] + def clip(self) -> tuple[bool, ...]: ... + @clip.setter + def clip(self, values: ArrayLike | None) -> None: ... + @overload + def __call__(self, values: tuple[np.ndarray, ...], clip: ArrayLike | bool | None = ...) -> tuple[np.ndarray, ...]: ... + @overload + def __call__(self, values: tuple[float, ...], clip: ArrayLike | bool | None = ...) -> tuple[float, ...]: ... + @overload + def __call__(self, values: ArrayLike, clip: ArrayLike | bool | None = ...) -> tuple: ... + def inverse(self, values: ArrayLike) -> tuple: ... + def autoscale(self, A: ArrayLike) -> None: ... + def autoscale_None(self, A: ArrayLike) -> None: ... + def scaled(self) -> bool: ... + @property + def n_components(self) -> int: ... + +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..96b14cfd26f7 100644 --- a/lib/matplotlib/container.py +++ b/lib/matplotlib/container.py @@ -1,129 +1,255 @@ -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._callbacks = cbook.CallbackRegistry(signals=["pchanged"]) + self._remove_method = None + self._label = str(label) if label is not None else None - self.eventson = False # fire events only if eventson - self._oid = 0 # an observer id - self._propobservers = {} # a dict from oids to funcs + def remove(self): + 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) - self._remove_method = None + def get_children(self): + return [child for child in cbook.flatten(self) if child is not None] - self.set_label(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_remove_method(self, f): - self._remove_method = f - def remove(self): - for c in self: - c.remove() +class BarContainer(Container): + """ + Container for the artists of bar plots (e.g. created by `.Axes.bar`). - if self._remove_method: - self._remove_method(self) + The container can be treated as a tuple of the *patches* themselves. + Additionally, you can access these and further parameters by the + attributes. - 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 + Attributes + ---------- + patches : list of :class:`~matplotlib.patches.Rectangle` + The artists of the bars. - def get_label(self): - """ - Get the label used for this artist in the legend. - """ - return self._label + errorbar : None or :class:`~matplotlib.container.ErrorbarContainer` + A container for the error bar artists if error bars are present. + *None* otherwise. - def set_label(self, s): + datavalues : None or array-like + The underlying data values corresponding to the bars. + + orientation : {'vertical', 'horizontal'}, default: None + If 'vertical', the bars are assumed to be vertical. + If 'horizontal', the bars are assumed to be horizontal. + + """ + + 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) + + @property + def bottoms(self): """ - Set the label to *s* for auto legend. + Return the values at the lower end of the bars. - ACCEPTS: string or anything printable with '%s' conversion. + .. versionadded:: 3.11 """ - if s is not None: - self._label = '%s' % (s, ) + if self.orientation == 'vertical': + return [p.get_y() for p in self.patches] + elif self.orientation == 'horizontal': + return [p.get_x() for p in self.patches] else: - self._label = None - self.pchanged() + raise ValueError("orientation must be 'vertical' or 'horizontal'.") - def add_callback(self, func): + @property + def tops(self): """ - Adds a callback function that will be called whenever one of - the :class:`Artist`'s properties changes. + Return the values at the upper end of the bars. - Returns an *id* that is useful for removing the callback with - :meth:`remove_callback` later. + .. versionadded:: 3.11 """ - oid = self._oid - self._propobservers[oid] = func - self._oid += 1 - return oid + if self.orientation == 'vertical': + return [p.get_y() + p.get_height() for p in self.patches] + elif self.orientation == 'horizontal': + return [p.get_x() + p.get_width() for p in self.patches] + else: + raise ValueError("orientation must be 'vertical' or 'horizontal'.") - def remove_callback(self, oid): + @property + def position_centers(self): """ - Remove a callback based on its *id*. - - .. seealso:: - - :meth:`add_callback` - For adding callbacks + Return the centers of bar positions. + .. versionadded:: 3.11 """ - try: - del self._propobservers[oid] - except KeyError: - pass + if self.orientation == 'vertical': + return [p.get_x() + p.get_width() / 2 for p in self.patches] + elif self.orientation == 'horizontal': + return [p.get_y() + p.get_height() / 2 for p in self.patches] + else: + raise ValueError("orientation must be 'vertical' or 'horizontal'.") - 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 get_children(self): - return list(cbook.flatten(self)) +class ErrorbarContainer(Container): + """ + Container for the artists of error bars (e.g. created by `.Axes.errorbar`). + The container can be treated as the *lines* tuple itself. + Additionally, you can access these and further parameters by the + attributes. -class BarContainer(Container): + Attributes + ---------- + lines : tuple + Tuple of ``(data_line, caplines, barlinecols)``. - def __init__(self, patches, errorbar=None, **kwargs): - self.patches = patches - self.errorbar = errorbar - Container.__init__(self, patches, **kwargs) + - 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. + has_xerr, has_yerr : bool + ``True`` if the errorbar has x/y errors. -class ErrorbarContainer(Container): + """ 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 PieContainer: + """ + Container for the artists of pie charts (e.g. created by `.Axes.pie`). + + .. versionadded:: 3.11 + + .. warning:: + The class name ``PieContainer`` name is provisional and may change in future + to reflect development of its functionality. + + You can access the wedge patches and further parameters by the attributes. + + Attributes + ---------- + wedges : list of `~matplotlib.patches.Wedge` + The artists of the pie wedges. + + values : `numpy.ndarray` + The data that the pie is based on. + + fracs : `numpy.ndarray` + The fraction of the pie that each wedge represents. + + texts : list of list of `~matplotlib.text.Text` + The artists of any labels on the pie wedges. Each inner list has one + text label per wedge. + + """ + def __init__(self, wedges, values, normalize): + self.wedges = wedges + self._texts = [] + self._values = values + self._normalize = normalize + + @property + def texts(self): + # Only return non-empty sublists. An empty sublist may have been added + # for backwards compatibility of the Axes.pie return value (see __getitem__). + return [t_list for t_list in self._texts if t_list] + + @property + def values(self): + result = self._values.copy() + result.flags.writeable = False + return result + + @property + def fracs(self): + if self._normalize: + result = self._values / self._values.sum() + else: + result = self._values + + result.flags.writeable = False + return result + + def add_texts(self, texts): + """Add a list of `~matplotlib.text.Text` objects to the container.""" + self._texts.append(texts) + + def remove(self): + """Remove all wedges and texts from the axes""" + for artist_list in self.wedges, self._texts: + for artist in cbook.flatten(artist_list): + artist.remove() + + def __getitem__(self, key): + # needed to support unpacking into a tuple for backward compatibility of the + # Axes.pie return value + return (self.wedges, *self._texts)[key] 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..772801b16d6d --- /dev/null +++ b/lib/matplotlib/container.pyi @@ -0,0 +1,82 @@ +from matplotlib.artist import Artist +from matplotlib.lines import Line2D +from matplotlib.collections import LineCollection +from matplotlib.patches import Rectangle, Wedge +from matplotlib.text import Text + +from collections.abc import Callable +from typing import Any, Literal +from numpy.typing import ArrayLike +from numpy import ndarray + +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: ... + @property + def bottoms(self) -> list[float]: ... + @property + def tops(self) -> list[float]: ... + @property + def position_centers(self) -> list[float]: ... + +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 PieContainer(Container): + wedges: list[Wedge] + def __init__( + self, + wedges: list[Wedge], + values: ndarray, + normalize: bool, + ) -> None: ... + @property + def texts(self) -> list[list[Text]]: ... + @property + def values(self) -> ndarray: ... + @property + def fracs(self) -> ndarray: ... + def add_texts(self, + texts: list[Text], + ) -> 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 4bceb7417d60..76481280729a 100644 --- a/lib/matplotlib/contour.py +++ b/lib/matplotlib/contour.py @@ -1,634 +1,488 @@ """ -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._contour as _contour -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., 'small', '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. + 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. - .. plot:: mpl_examples/pylab_examples/contour_demo.py - """ + zorder : float or None, default: ``(2 + contour.get_zorder())`` + zorder of the contour labels. - """ - NOTES on how this all works: + Returns + ------- + labels + A list of `.Text` instances for the labels. - 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. - - Once these attributes are set, clabel passes control to the - labels method (case of automatic label placement) or - BlockingContourLabeler (case of manual label placement). + Note: The returned Text instances should not be individually + removed or have their geometry modified, e.g. by changing text or font size. + If you need such a modification, remove the entire + `.ContourSet` and recreate it. """ - 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: + if self.filled: + _api.warn_deprecated( + "3.11", + message="clabel() is not designed to be used with filled contours and " + "may result in inconsistent plots. Applying clabel() to filled " + "contours is thus deprecated since %(since)s. If you need " + "labels with filled contours, instead draw contour lines " + "using contour() in addition to contourf() and add the labels " + "to the contour lines." + ) + + # 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.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) - - # There must be a more efficient way... - lc = [tuple(l) for l in linecontour] - dind = lc.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 = self.axes.convert_xunits(x) + y = self.axes.convert_yunits(y) + 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""" @@ -637,241 +491,252 @@ 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) - - -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): + self._paths[icon] = Path.make_compound_path(*additions) + + def remove(self): + super().remove() + for text in self.labelTexts: + try: + text.remove() + except ValueError: + _api.warn_external( + "Some labels were manually removed from the ContourSet. " + "To remove labels cleanly, remove the entire ContourSet " + "and recreate it.") + self.labelTexts.clear() + + +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, + **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``. - - level0segs = [polygon0, polygon1, ...] + filled contour regions ``len(allsegs) = len(levels)-1``. The lists + should look like :: - 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). - - level0kinds = [polygon0kinds, ...] + If not ``None``, ``len(allkinds) == len(allsegs)``. The lists + should look like :: - polygon0kinds = [vertexcode0, vertexcode1, ...] + level0kinds = [polygon0kinds, ...] + polygon0kinds = [vertexcode0, vertexcode1, ...] - If *allkinds* is not *None*, usually all polygons for a particular - contour level are grouped together so that + If *allkinds* is not ``None``, usually all polygons for a + particular contour level are grouped together so that + ``level0segs = [polygon0]`` and ``level0kinds = [polygon0kinds]``. - 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, + 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 "color" in kwargs: + raise _api.kwarg_error("ContourSet.__init__", "color") + + 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 @@ -879,108 +744,89 @@ 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) - - if use_set_under_over: - if extend_min: - cmap.set_under(self.colors[0]) - if extend_max: - cmap.set_over(self.colors[-1]) + cmap = mcolors.ListedColormap( + cbook._resize_sequence(color_sequence[i0:], ncolors), + under=(color_sequence[0] + if use_set_under_over and self._extend_min else None), + over=(color_sequence[-1] + if use_set_under_over and self._extend_max else None), + ) - 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) - # 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) + self.set(edgecolor="none") 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), + label="_nolegend_", + # Default zorder taken from LineCollection, which is higher + # than for filled contours so that lines are displayed on top. + zorder=2, + ) + self.set(**kwargs) # Let user-set values override defaults. + + 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 + 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): @@ -993,55 +839,55 @@ def __getstate__(self): 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 @@ -1049,57 +895,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]: @@ -1112,33 +963,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 _autolev(self, z, N): + 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): """ Select contour levels to span the data. @@ -1149,46 +1010,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): """ @@ -1199,40 +1066,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 @@ -1257,55 +1123,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))) @@ -1316,282 +1174,271 @@ 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. + # 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. - 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() - - 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 self._cm_set( + paths=[paths[idx]], + 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` + This class is typically not instantiated directly by the user but by + `~.Axes.contour` and `~.Axes.contourf`. - Useful attributes: - ax: - The axes object in which the contours are drawn - - collections: - A silent_list of LineCollections or PolyCollections - - levels: - Contour levels - - 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): + 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 - if self._corner_mask == 'legacy': - contour_generator = args[0].Cntr - else: - contour_generator = args[0]._contour_generator + contour_generator = args[0]._contour_generator + self._mins = args[0]._mins + self._maxs = args[0]._maxs + self._algorithm = args[0]._algorithm else: - x, y, z = self._contour_args(args, kwargs) + import contourpy - _mask = ma.getmask(z) - if _mask is ma.nomask or not _mask.any(): - _mask = None + algorithm = mpl._val_or_rc(algorithm, 'contour.algorithm') + mpl.rcParams.validate["contour.algorithm"](algorithm) + self._algorithm = algorithm - self._corner_mask = kwargs.get('corner_mask', None) - if self._corner_mask is None: - self._corner_mask = mpl.rcParams['contour.corner_mask'] + 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 - if self._corner_mask == 'legacy': - cbook.warn_deprecated('1.5', - name="corner_mask='legacy'", - alternative='corner_mask=False or True') - contour_generator = _cntr.Cntr(x, y, z.filled(), _mask) - else: - contour_generator = _contour.QuadContourGenerator( - x, y, z.filled(), _mask, self._corner_mask, self.nchunk) + x, y, z = self._contour_args(args, kwargs) + + 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_separately(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)] - if self._corner_mask == 'legacy': - self.Cntr = contour_generator - else: - self._contour_generator = contour_generator + 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): - if self._corner_mask == 'legacy': - nlist = self.Cntr.trace(level, level_upper, - nchunk=self.nchunk) - nseg = len(nlist) // 2 - vertices = nlist[:nseg] - kinds = nlist[nseg:] - else: - vertices, kinds = \ - self._contour_generator.create_filled_contour( - level, level_upper) - allsegs.append(vertices) - allkinds.append(kinds) - else: - allkinds = None - for level in self.levels: - if self._corner_mask == 'legacy': - nlist = self.Cntr.trace(level) - nseg = len(nlist) // 2 - vertices = nlist[:nseg] - else: - vertices = self._contour_generator.create_contour(level) - allsegs.append(vertices) - 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 @@ -1599,7 +1446,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 @@ -1609,7 +1456,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. @@ -1625,223 +1475,273 @@ 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+2* "nice" contour level boundaries + between the minimum and maximum numeric values of *Z*. These boundaries + define where lines are drawn (for `contour`) or where filled regions + are separated (for `contourf`). - *X*, *Y* specify the (x, y) coordinates of the surface + If not given, a reasonable default is chosen; for linear scales, + *n*=7 is the default. - :: + If array-like, draw contour lines at the specified levels. + The values must be in increasing order. - contour(Z,N) - contour(X,Y,Z,N) + If not specified, a reasonable default is automatically chosen. For + linear scales, this corresponds to *levels=7*. For logarithmic + scales, `~matplotlib.ticker.LogLocator` is used instead. - contour *N* automatically-chosen levels. +Returns +------- +`~.contour.QuadContourSet` - :: +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(Z,V) - contour(X,Y,Z,V) +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`. - draw contour lines at the values specified in sequence *V* + The sequence is cycled for the levels in ascending order. If the + sequence is shorter than the number of levels, it's repeated. - :: + 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. - contourf(..., V) + .. versionchanged:: 3.10 + Previously a single color had to be expressed as a string, but now any + valid color format may be passed. - fill the ``len(V)-1`` regions between the values in *V* + By default (value *None*), the colormap specified by *cmap* + will be used. - :: +alpha : float, default: 1 + The alpha blending value, between 0 (transparent) and 1 (opaque). - contour(Z, **kwargs) +%(cmap_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*. +%(norm_doc)s - ``C = contour(...)`` returns a - :class:`~matplotlib.contour.QuadContourSet` object. + This parameter is ignored if *colors* is set. - Optional keyword arguments: +%(vmin_vmax_doc)s - *corner_mask*: [ *True* | *False* | 'legacy' ] - 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. - If 'legacy', the old contouring algorithm is used, which is - equivalent to *False* and is deprecated, only remaining whilst the - new algorithm is tested fully. + If *vmin* or *vmax* are not given, the default color scaling is based on + *levels*. - If not specified, the default is taken from - rcParams['contour.corner_mask'], which is True unless it has - been modified. + 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']. - - *nchunk*: [ 0 | integer ] - 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*. - - contour-only keyword arguments: - - *linewidths*: [ *None* | number | tuple of numbers ] - If *linewidths* is *None*, the default width in - ``lines.linewidth`` in ``matplotlibrc`` is used. +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`. - If a number, all levels will be plotted with this linewidth. +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*. - If a tuple, different levels will be plotted with different - linewidths in the order specified. +linewidths : float or array-like, default: :rc:`contour.linewidth` + *Only applies to* `.contour`. - *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. + The line width of the contour lines. - *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 a number, all levels will be plotted with this linewidth. - contourf-only keyword arguments: - - *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 a sequence, the levels in ascending order will be plotted with + the linewidths in the order specified. + If None, this falls back to :rc:`lines.linewidth`. - Note: contourf fills intervals that are closed at the top; that - is, for boundaries *z1* and *z2*, the filled region is:: +linestyles : {*None*, 'solid', 'dashed', 'dashdot', 'dotted'}, optional + *Only applies to* `.contour`. - z1 < z <= z2 + 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. - 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. + *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. - **Examples:** +negative_linestyles : {*None*, 'solid', 'dashed', 'dashdot', 'dotted'}, \ + optional + *Only applies to* `.contour`. - .. plot:: mpl_examples/pylab_examples/contour_demo.py + If *linestyles* is *None* and the lines are monochrome, this argument + specifies the line style for negative contours. - .. plot:: mpl_examples/pylab_examples/contourf_demo.py + If *negative_linestyles* is *None*, the default is taken from + :rc:`contour.negative_linestyle`. - .. plot:: mpl_examples/pylab_examples/contour_corner_mask.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. + +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..225ca8e6ce76 --- 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,274 @@ 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 a `numpy.ndarray` of np.datetime64 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 -class strpdate2num(object): + dt[np.isnat(d)] = np.nan + return dt + + +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 +402,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] + masked = np.ma.is_masked(d) + mask = np.ma.getmask(d) + d = np.asarray(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 + # 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]') + d = np.ma.masked_array(d, mask=mask) if masked else d + d = _dt64_to_ordinalf(d) -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 + 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. - Return value is a :class:`datetime` instance in timezone *tz* (default to - rcparams TZ value). + 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") - 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)) @@ -367,180 +535,339 @@ def drange(dstart, dend, delta): # calculate end of the interval which will be generated dinterval_end = dstart + num * delta - # ensure, that an half open interval will be generated [dstart, dend) + # ensure, that a 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): + + offset_string = _api.deprecate_privatize_attribute( + "3.11", alternative="get_offset()" + ) + + 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 + + def get_offset(self): + return self._offset_string - return cbook.unicode_safe(dt.strftime(self.fmt)) + 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 +877,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 +1122,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 +1141,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 +1151,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 +1293,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 +1305,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 +1378,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 +1396,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 +1460,297 @@ 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, list of int, constant from :mod:`dateutil.rrule`, or \ + list of constants, default: 1 (Tuesday) + Ticks will be placed on every weekday in *byweekday*. Default is + every Tuesday. + + Elements of *byweekday* (if a sequence) must be either integers or + 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 __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_view_interval(self, vmin, vmax): - self._wrapped_locator.set_view_interval(vmin, vmax) - return DateLocator.set_view_interval(self, vmin, vmax) + return self.tick_values(dmin, dmax) - def set_data_interval(self, vmin, vmax): - self._wrapped_locator.set_data_interval(vmin, vmax) - return DateLocator.set_data_interval(self, vmin, vmax) + 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 - 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] + 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 +1758,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 +1786,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/dates.pyi b/lib/matplotlib/dates.pyi new file mode 100644 index 000000000000..426082679393 --- /dev/null +++ b/lib/matplotlib/dates.pyi @@ -0,0 +1,37 @@ +import datetime +from collections.abc import Sequence +from typing import overload + +import numpy as np +import numpy.typing as npt + +TZ = str | datetime.tzinfo + +def _get_tzinfo(tz: TZ | None=None) -> datetime.tzinfo: ... +def _reset_epoch_test_example() -> None: ... +def set_epoch(epoch: str) -> None: ... +def get_epoch() -> str: ... +def _dt64_to_ordinalf(d: npt.NDArray[np.datetime64]) -> npt.NDArray[np.floating]: ... +def _from_ordinalf(x: float, tz: TZ | None=None) -> datetime.datetime: ... +# Ideally str | Sequence[str] would get an override, but because a str is a valid Sequence[str], +# it's not possible to distinguish between them in the type system +# See https://github.com/python/typing/issues/256 +def datestr2num(d: str | Sequence[str], default: datetime.datetime | None=None) -> float | npt.NDArray[np.floating]: ... + +@overload +def date2num(d: datetime.datetime | np.datetime64) -> float: ... +@overload +def date2num(d: Sequence[datetime.datetime] | Sequence[np.datetime64]) -> npt.NDArray[np.floating]: ... + +@overload +def num2date(x: float, tz: TZ | None=None) -> datetime.datetime: ... +@overload +def num2date(x: Sequence[float], tz: TZ | None=None) -> list[datetime.datetime]: ... + +@overload +def num2timedelta(x: float) -> datetime.timedelta: ... +@overload +def num2timedelta(x: Sequence[float]) -> list[datetime.timedelta]: ... + +def drange(dstart: datetime.datetime, dend: datetime.datetime, delta: datetime.timedelta) -> npt.NDArray[np.floating]: ... +def _wrap_in_tex(text: str) -> str: ... 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 550f864d2156..000000000000 --- a/lib/matplotlib/delaunay/natneighbors.cpp +++ /dev/null @@ -1,297 +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..979744d1ef5c 100644 --- a/lib/matplotlib/dviread.py +++ b/lib/matplotlib/dviread.py @@ -1,101 +1,285 @@ """ -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, cached_property, lru_cache, partial, wraps +from pathlib import Path -if six.PY3: - def ord(x): - return x +import fontTools.agl +import numpy as np + +import matplotlib as mpl +from matplotlib import _api, cbook, font_manager +from matplotlib.ft2font import LoadFlags + +_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) + +_dvistate = enum.Enum('DviState', 'pre outer inpage post_post finale') + +# 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') + + +# Also a namedtuple, for backcompat. +class Text(namedtuple('Text', 'x y font glyph width')): + """ + A glyph in the dvi file. + + In order to render the glyph, load the glyph at index ``text.index`` + from the font at ``text.font.resolve_path()`` with size ``text.font.size``, + warped with ``text.font.effects``, then draw it at position + ``(text.x, text.y)``. + + ``text.glyph`` is the glyph number actually stored in the dvi file (whose + interpretation depends on the font). ``text.width`` is the glyph width in + dvi units. + """ + + @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) + + font_path = property(lambda self: self.font.resolve_path()) + font_size = property(lambda self: self.font.size) + font_effects = property(lambda self: self.font.effects) + + @property # To be deprecated together with font_path, font_size, font_effects. + def glyph_name_or_index(self): + """ + The glyph name, the native charmap glyph index, or the raw glyph index. + + If the font is a TrueType file (which can currently only happen for + DVI files generated by xetex or luatex), then this number is the raw + index of the glyph, which can be passed to FT_Load_Glyph/load_glyph. + + Otherwise, the font is a PostScript font. For such fonts, if + :file:`pdftex.map` specifies an encoding for this glyph's font, + that is a mapping of glyph indices to Adobe glyph names; which + is used by this property to convert dvi numbers 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 for a PostScript font, + this number is an index to the font's "native" charmap; glyphs should + directly load using FT_Load_Char/load_char after selecting the native + charmap. + """ + # The last section is only true on luatex since luaotfload 3.23; this + # must be checked by the code generated by texmanager. (luaotfload's + # docs states "No one should rely on the mapping between DVI character + # codes and font glyphs [prior to v3.15] unless they tightly + # control all involved versions and are deeply familiar with the + # implementation", but a further mapping bug was fixed in luaotfload + # commit 8f2dca4, first included in v3.23). + entry = PsfontsMap(find_tex_file("pdftex.map"))[self.font.texname] + return (_parse_enc(entry.encoding)[self.glyph] + if entry.encoding is not None else self.glyph) + + def _as_unicode_or_name(self): + if self.font.subfont: + raise NotImplementedError("Indexing TTC fonts is not supported yet") + path = self.font.resolve_path() + if path.name.lower().endswith("pk"): + # PK fonts have no encoding information; report glyphs as ASCII but + # with a "?" to indicate that this is just a guess. + return (f"{chr(self.glyph)}?" if chr(self.glyph).isprintable() else + f"pk{self.glyph:#02x}") + face = font_manager.get_font(path) + glyph_name = face.get_glyph_name(self.index) + glyph_str = fontTools.agl.toUnicode(glyph_name) + return glyph_str or glyph_name + + +# 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 -_dvistate = mpl_cbook.Bunch(pre=0, outer=1, inpage=2, post_post=3, finale=4) -class Dvi(object): +class Dvi: """ - 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 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 +288,571 @@ 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), - 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)) + newf = DviFont(scale=_mul1220(scale, f._scale), + metrics=f._metrics, texname=f.texname, vf=f._vf) + 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:] + if fontname.startswith(b"[") and c == 0x4c756146: # c == "LuaF" + # See https://chat.stackexchange.com/rooms/106428 (and also + # https://tug.org/pipermail/dvipdfmx/2021-January/000168.html). + # AFAICT luatex's dvi drops info re: OpenType variation-axis values. + self.fonts[k] = DviFont.from_luatex(s, n) + return + fontname = fontname.decode("ascii") + try: + tfm = _tfmfile(fontname) + except FileNotFoundError as exc: + if fontname.startswith("[") and fontname.endswith(";") and c == 0: + exc.add_note( + "This dvi file was likely generated with a too-old " + "version of luaotfload; luaotfload 3.23 is required.") + # 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')) - - self.fonts[k] = DviFont(scale=s, tfm=tfm, texname=n, vf=vf) + raise ValueError(f'tfm checksum mismatch: {n}') + try: + vf = _vffile(fontname) + except FileNotFoundError: + vf = None + self.fonts[k] = DviFont(scale=s, metrics=tfm, texname=n, vf=vf) + + @_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 not in [2, 7]: # 2: pdftex, luatex; 7: xetex + 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 - def _post(self): - if self.state != _dvistate.outer: - raise ValueError("misplaced post in dvi file") + @_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 + @_dispatch(249, args=()) def _post_post(self): raise NotImplementedError -class DviFont(object): + @_dispatch(250, args=()) + def _begin_reflect(self): + raise NotImplementedError + + @_dispatch(251, args=()) + def _end_reflect(self): + raise NotImplementedError + + @_dispatch(252, args=()) + def _define_native_font(self): + k = self._read_arg(4, signed=False) + s = self._read_arg(4, signed=False) + flags = self._read_arg(2, signed=False) + l = self._read_arg(1, signed=False) + n = self.file.read(l) + i = self._read_arg(4, signed=False) + effects = {} + if flags & 0x0200: + effects["rgba"] = [self._read_arg(1, signed=False) for _ in range(4)] + if flags & 0x1000: + effects["extend"] = self._read_arg(4, signed=True) / 65536 + if flags & 0x2000: + effects["slant"] = self._read_arg(4, signed=True) / 65536 + if flags & 0x4000: + effects["embolden"] = self._read_arg(4, signed=True) / 65536 + self.fonts[k] = DviFont.from_xetex(s, n, i, effects) + + @_dispatch(253, args=()) + def _set_glyphs(self): + w = self._read_arg(4, signed=False) + k = self._read_arg(2, signed=False) + xy = [self._read_arg(4, signed=True) for _ in range(2 * k)] + g = [self._read_arg(2, signed=False) for _ in range(k)] + font = self.fonts[self.f] + for i in range(k): + self.text.append(Text(self.h + xy[2 * i], self.v + xy[2 * i + 1], + font, g[i], font._width_of(g[i]))) + self.h += w + + @_dispatch(254, args=()) + def _set_text_and_glyphs(self): + l = self._read_arg(2, signed=False) + t = self.file.read(2 * l) # utf16 + w = self._read_arg(4, signed=False) + k = self._read_arg(2, signed=False) + xy = [self._read_arg(4, signed=True) for _ in range(2 * k)] + g = [self._read_arg(2, signed=False) for _ in range(k)] + font = self.fonts[self.f] + for i in range(k): + self.text.append(Text(self.h + xy[2 * i], self.v + xy[2 * i + 1], + font, g[i], font._width_of(g[i]))) + self.h += w + + @_dispatch(255) + def _malformed(self, raw): + raise ValueError("unknown command: byte 255") + + +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. + metrics : Tfm | TtfMetrics + TeX font metrics for this font + texname : bytes + Name of the font as used internally in the DVI file, 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 + def __init__(self, scale, metrics, texname, vf): + _api.check_isinstance(bytes, texname=texname) + self._scale = scale + self._metrics = metrics + self.texname = texname + self._vf = vf + self._path = None + self._encoding = None + + @classmethod + def from_luatex(cls, scale, texname): + path_b, sep, rest = texname[1:].rpartition(b"]") + if not (texname.startswith(b"[") and sep and rest[:1] in [b"", b":"]): + raise ValueError(f"Invalid modern font name: {texname}") + # utf8 on Windows, not utf16! + path = path_b.decode("utf8") if os.name == "nt" else os.fsdecode(path_b) + subfont = 0 + effects = {} + if rest[1:]: + for kv in rest[1:].decode("ascii").split(";"): + key, val = kv.split("=", 1) + if key == "index": + subfont = val + elif key in ["embolden", "slant", "extend"]: + effects[key] = int(val) / 65536 + else: + _log.warning("Ignoring invalid key-value pair: %r", kv) + metrics = TtfMetrics(path) + font = cls(scale, metrics, texname, vf=None) + font._path = Path(path) + font.subfont = subfont + font.effects = effects + return font + + @classmethod + def from_xetex(cls, scale, texname, subfont, effects): + # utf8 on Windows, not utf16! + path = texname.decode("utf8") if os.name == "nt" else os.fsdecode(texname) + metrics = TtfMetrics(path) + font = cls(scale, metrics, b"[" + texname + b"]", vf=None) + font._path = Path(path) + font.subfont = subfont + font.effects = effects + return font + + size = property(lambda self: self._scale * (72.0 / (72.27 * 2**16))) + + 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') + + @property + def face_index(self): # For compatibility with FT2Font. + return 0 - Widths of glyphs in glyph-space units, typically 1/1000ths of - the point size. + def _get_fontmap(self, string): + """Get the mapping from characters to the font that includes them. - """ - __slots__ = ('texname', 'size', 'widths', '_scale', '_vf', '_tfm') - - 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 - 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) ] + 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._metrics.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. - """ + """Height and depth of char in dvi units.""" + metrics = self._metrics.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 resolve_path(self): + if self._path is None: + fontmap = PsfontsMap(find_tex_file("pdftex.map")) + try: + psfont = fontmap[self.texname] + except LookupError as exc: + try: + find_tex_file(f"{self.texname.decode('ascii')}.mf") + except FileNotFoundError: + raise exc from None + else: + self._path = Path(find_tex_file( + f"{self.texname.decode('ascii')}.600pk")) + else: + 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"))) + self._path = Path(psfont.filename) + return self._path + + @cached_property + def subfont(self): + return 0 - 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) + @cached_property + def effects(self): + if self.resolve_path().match("*.600pk"): + return {} + return PsfontsMap(find_tex_file("pdftex.map"))[self.texname].effects + + 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: + # - for xetex & luatex "native fonts", dvi indices are directly equal + # to FreeType indices. + # - 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. + if self.texname.startswith(b"["): + return idx + if self._encoding is None: + face = font_manager.get_font(self.resolve_path()) + psfont = PsfontsMap(find_tex_file("pdftex.map"))[self.texname] + 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. - vf = Vf(filename) - glyph = vf[code] - glyph.text, glyph.boxes, glyph.width + Examples + -------- + :: + + 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 +860,204 @@ 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})) + + +class TtfMetrics: + def __init__(self, filename): + self._face = font_manager.get_font(filename) + + def get_metrics(self, idx): + # _mul1220 uses a truncating bitshift for compatibility with dvitype. + # When upem is 2048 the conversion to 12.20 is exact, but when + # upem is 1000 (e.g. lmroman10-regular.otf) the metrics themselves + # are not exactly representable as 12.20 fp. Manual testing via + # \sbox0{x}\count0=\wd0\typeout{\the\count0} suggests that metrics + # are rounded (not truncated) after conversion to 12.20 and before + # multiplication by the scale. + upem = self._face.units_per_EM # Usually 2048 or 1000. + g = self._face.load_glyph(idx, LoadFlags.NO_SCALE) + return TexMetrics( + tex_width=round(g.horiAdvance / upem * 2**20), + tex_height=round(g.horiBearingY / upem * 2**20), + tex_depth=round((g.height - g.horiBearingY) / upem * 2**20), + ) + + +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 +1069,316 @@ 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. - - Usage (subject to change):: - - for name in Encoding(filename): - whatever(name) + 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") + + +class _LuatexKpsewhich: + @cache # A singleton. + def __new__(cls): + self = object.__new__(cls) + self._proc = self._new_proc() + return self + + def _new_proc(self): + return subprocess.Popen( + ["luatex", "--luaonly", str(cbook._get_data_path("kpsewhich.lua"))], + # mktexpk logs to stderr; suppress that. + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, + # Store generated pk fonts in our own cache. + env={"MT_VARTEXFONTS": str(Path(mpl.get_cachedir(), "vartexfonts")), + **os.environ}) + + 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) + + +@lru_cache +def find_tex_file(filename): """ - __slots__ = ('encoding',) + Find a file in the texmf tree using kpathsea_. - 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') + 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. - 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) + .. _kpathsea: https://www.tug.org/kpathsea/ - return result + Parameters + ---------- + filename : str or path-like -def find_tex_file(filename, format=None): + Raises + ------ + FileNotFoundError + If the file is not found. """ - 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. - - 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) - .. seealso:: - - `Kpathsea documentation `_ - The library that :program:`kpsewhich` is part of. - """ + # 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') - 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): try: - return cache[texname] - except KeyError: - pass + lk = _LuatexKpsewhich() + except (FileNotFoundError, OSError): + 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: - result = None + 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 = {'env': {**os.environ}, + 'encoding': sys.getfilesystemencoding(), + 'errors': 'surrogateescape'} + kwargs['env'].update( + MT_VARTEXFONTS=str(Path(mpl.get_cachedir(), "vartexfonts"))) - cache[texname] = result - return result + try: + path = cbook._check_and_log_subprocess( + ['kpsewhich', '-mktex=pk', filename], _log, **kwargs, + ).rstrip('\n') + except (FileNotFoundError, OSError, RuntimeError): + path = None + + if path: + return path + else: + raise FileNotFoundError( + f"Matplotlib's TeX implementation searched for a file named " + f"{filename!r} in your texmf tree, but could not find it") -def _tfmfile(texname): - return _fontfile(texname, Tfm, '.tfm', _tfmcache) -def _vffile(texname): - return _fontfile(texname, Vf, '.vf', _vfcache) +@lru_cache +def _fontfile(cls, suffix, texname): + return cls(find_tex_file(texname + suffix)) +_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 + + parser = ArgumentParser() + parser.add_argument("filename") + parser.add_argument("dpi", nargs="?", type=float, default=None) + parser.add_argument("-d", "--debug", action="store_true") + args = parser.parse_args() + + if args.debug: + logging.basicConfig(level=logging.DEBUG) + + def _print_fields(*args): + print(" ".join(map("{:>11}".format, args))) + + with Dvi(args.filename, args.dpi) as dvi: + 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): + font_name = (font.texname.decode("utf8") if os.name == "nt" + else os.fsdecode(font.texname)) + if isinstance(font._metrics, Tfm): + print(f"font: {font_name} at {font.resolve_path()}") + else: + print(f"font: {font_name}") + print(f"scale: {font._scale / 2 ** 20}") + _print_fields("x", "y", "glyph", "chr", "w") + for text in group: + _print_fields(text.x, text.y, text.glyph, + text._as_unicode_or_name(), 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..de429bd0b7f1 --- /dev/null +++ b/lib/matplotlib/dviread.pyi @@ -0,0 +1,128 @@ +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 import Self + +from .ft2font import CharacterCodeType, GlyphIndexType + + +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: CharacterCodeType + 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) -> GlyphIndexType: ... # type: ignore[override] + @property + def glyph_name_or_index(self) -> GlyphIndexType | 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 + def __init__( + self, scale: float, metrics: Tfm | TtfMetrics, texname: bytes, vf: Vf | None + ) -> None: ... + @classmethod + def from_luatex(cls, scale: float, texname: bytes) -> DviFont: ... + @classmethod + def from_xetex( + cls, scale: float, texname: bytes, subfont: int, effects: dict[str, float] + ) -> DviFont: ... + def __eq__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... + @property + def size(self) -> float: ... + @property + def widths(self) -> list[int]: ... + @property + def fname(self) -> str: ... + @property + def face_index(self) -> int: ... + def resolve_path(self) -> Path: ... + @property + def subfont(self) -> int: ... + @property + def effects(self) -> dict[str, float]: ... + +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 TtfMetrics: + def __init__(self, filename: str | os.PathLike) -> None: ... + def get_metrics(self, idx: int) -> TexMetrics: ... + +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 986870c78140..ad0206e0db5c 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1,1730 +1,3740 @@ """ -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('') - def get(self, key): + 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_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._remove_method = functools.partial(self._remove_suplabel, + name=info['name']) + + suplab._autopos = autopos + self.stale = True + return suplab + + def _remove_suplabel(self, label, name): + self.texts.remove(label) + setattr(self, name, None) + + @_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) - # 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.callbacks = cbook.CallbackRegistry() + The Axes of the subplot. The returned Axes can actually be an + instance of a subclass, such as `.projections.polar.PolarAxes` for + polar projections. - 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) + 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. - self.frameon = frameon + %(Axes:kwdoc)s - self.transFigure = BboxTransformTo(self.bbox) + See Also + -------- + .Figure.add_axes + .pyplot.subplot + .pyplot.axes + .Figure.subplots + .pyplot.subplots - # 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) + Examples + -------- + :: - self._hold = rcParams['axes.hold'] - self.canvas = None - self._suptitle = None + fig = plt.figure() - if subplotpars is None: - subplotpars = SubplotParams() + fig.add_subplot(231) + ax1 = fig.add_subplot(2, 3, 1) # equivalent but more general - self.subplotpars = subplotpars - self.set_tight_layout(tight_layout) + 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._axstack = AxesStack() # track all figure axes and current axes - self.clf() - self._cachedRenderer = None + 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") - # 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. + 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. - 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) + 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 show(self, warn=True): - """ - If using a GUI backend with pyplot, display the figure window. + See Also + -------- + .pyplot.subplots + .Figure.add_subplot + .pyplot.subplot - 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. + Examples + -------- + :: - For non-GUI backends, this does nothing, in which case - a warning will be issued if *warn* is True (default). + # 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 = grouper.get_siblings(ax, include_self=False) + 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): """ - 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() + Clear the figure. - axes = property(fget=_get_axes, doc="Read-only: list of axes in Figure") + Parameters + ---------- + keep_observers : bool, default: False + Set *keep_observers* to True if, for example, + a gui widget is tracking the Axes in the figure. + """ + self.suppressComposite = None - def _get_dpi(self): - return self._dpi + # first clear the Axes in any subfigures + for subfig in self.subfigs: + subfig.clear(keep_observers=keep_observers) + self.subfigs = [] - 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) + for ax in tuple(self.axes): # Iterate over the copy. + ax.clear() + self.delaxes(ax) # Remove ax from self._axstack. - def get_tight_layout(self): - """ - Return the Boolean flag, True to use :meth`tight_layout` when drawing. - """ - return self._tight + 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 set_tight_layout(self, tight): + self.stale = True + + # 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. + + .. admonition:: Discouraged - When providing a dict containing the keys `pad`, `w_pad`, `h_pad` - and `rect`, the default :meth:`tight_layout` paddings will be - overridden. + The use of ``clf()`` is discouraged. Use ``clear()`` instead. - ACCEPTS: [True | False | dict | None ] + 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. - e.g.:: + Returns + ------- + `~matplotlib.legend.Legend` - hold() # toggle hold - hold(True) # hold is on - hold(False) # hold is off + Other Parameters + ---------------- + %(_legend_kw_figure)s + + 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` - figimage(X, xo, yo) + Other Parameters + ---------------- + **kwargs : `~matplotlib.text.Text` properties + Other miscellaneous text parameters. - with pixel offsets *xo*, *yo*, + %(Text:kwdoc)s - *X* must be a float array: + 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. + + 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 set_size_inches(self, *args, **kwargs): + 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 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 + + Notes + ----- + This assumes that all Axes in ``axs`` are from the same `.GridSpec`, + so that their `.SubplotSpec` positions correspond to figure positions. - ACCEPTS: a w,h tuple with w,h in inches + 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 - """ - self.bbox_inches.x1 = val + (axes_proj_class, proj_class_kwargs) - def set_figheight(self, val): + which can be used for new Axes initialization/identification. """ - Set the height of the figure in inches + 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: + + 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 - ACCEPTS: float + def get_default_bbox_extra_artists(self): """ - self.bbox_inches.y1 = val + 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 - def set_frameon(self, b): + def get_tightbbox(self, renderer=None, *, bbox_extra_artists=None): """ - Set whether the figure frame (background) is displayed or invisible + Return a (tight) bounding box of the figure *in inches*. + + 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()``) - ACCEPTS: boolean + 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). """ - self.frameon = b - 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) + 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 - def _make_key(self, *args, **kwargs): - 'make a hashable key out of args and kwargs' + for a in artists: + bbox = a.get_tightbbox(renderer) + if bbox is not None: + bb.append(bbox) - 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: - # some objects can define __getitem__ without being - # iterable and in those cases the conversion to tuples - # will fail. So instead of using the iterable(v) function - # we simply try and convert to a tuple, and proceed if not. + 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: - v = tuple(v) - except Exception: - pass - ret.append((k, v)) - return tuple(ret) - - def fixlist(args): - ret = [] - for a in args: - if iterable(a): - a = tuple(a) - ret.append(a) - return tuple(ret) - - key = fixlist(args), fixitems(six.iteritems(kwargs)) - return key - - @docstring.dedent_interpd - def add_axes(self, *args, **kwargs): + 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): """ - 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) + Build a layout of Axes based on ASCII art or nested lists. - 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:: + This is a helper function to build complex GridSpec layouts visually. - fig.add_axes(rect, label='axes1') - fig.add_axes(rect, label='axes2') + See :ref:`mosaic` + for an example and full API documentation - 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:: + Parameters + ---------- + mosaic : list of list of {hashable or nested} or str - fig.add_axes(ax) + A visual layout of how you want your Axes to be arranged + labeled as strings. For example :: - In all cases, the :class:`~matplotlib.axes.Axes` instance - will be returned. + x = [['A panel', 'A panel', 'edge'], + ['C panel', '.', 'edge']] - In addition to *projection*, the following kwargs are supported: + produces 4 Axes: - %(Axes)s - """ - if not len(args): - return + - '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 - # 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 + Any of the entries in the layout can be a list of lists + of the same form to create nested layouts. - 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 + If input is a str, then it can either be a multi-line string of + the form :: - @docstring.dedent_interpd - def add_subplot(self, *args, **kwargs): - """ - Add a subplot. Examples:: + ''' + AAE + C.E + ''' + + 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 ``;``:: + + 'AB;CC' + + The string notation allows only single character Axes labels and + does not support nesting but is very terse. - fig.add_subplot(111) + The Axes identifiers may be `str` or a non-iterable hashable + object (e.g. `tuple` s may not be used). - # equivalent but more general - fig.add_subplot(1,1,1) + 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. - # add subplot with red background - fig.add_subplot(212, axisbg='r') + 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. - # add a polar subplot - fig.add_subplot(111, projection='polar') + 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. - # add Subplot instance sub - fig.add_subplot(sub) + 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*. - *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`. + 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*. - The :class:`~matplotlib.axes.Axes` instance will be returned. + 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")``. - If the figure already has a subplot with key (*args*, - *kwargs*) then it will simply make that subplot current and - return it. + .. versionadded:: 3.7 - .. seealso:: :meth:`~matplotlib.pyplot.subplot` for an - explanation of the args. + 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) + + +@_docstring.interpd +class SubFigure(FigureBase): + """ + Logical figure that can be placed inside a figure. - The following kwargs are supported: + 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:: - %(Axes)s + fig = plt.figure() + sfigs = fig.subfigures(1, 2) + axsL = sfigs[0].subplots(1, 2) + axsR = sfigs[1].subplots(2, 1) + + See :doc:`/gallery/subplots_axes_and_figures/subfigures` + """ + + def __init__(self, parent, subplotspec, *, + facecolor=None, + edgecolor=None, + linewidth=0.0, + frameon=None, + **kwargs): """ - if not len(args): - return + Parameters + ---------- + parent : `.Figure` or `.SubFigure` + Figure or subfigure that contains the SubFigure. SubFigures + can be nested. - 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))) + subplotspec : `.gridspec.SubplotSpec` + Defines the region in a parent gridspec where the subfigure will + be placed. - if isinstance(args[0], SubplotBase): + facecolor : default: ``"none"`` + The figure patch face color; transparent by default. - 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) + edgecolor : default: :rc:`figure.edgecolor` + The figure patch edge color. - # try to find the axes with this key in the stack - ax = self._axstack.get(key) + linewidth : float + The linewidth of the frame (i.e. the edge linewidth of the figure + patch). - 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) + frameon : bool, default: :rc:`figure.frameon` + If ``False``, suppress drawing the figure background patch. - a = subplot_class_factory(projection_class)(self, *args, **kwargs) + Other Parameters + ---------------- + **kwargs : `.SubFigure` properties, optional - self._axstack.add(key, a) - self.sca(a) - return a + %(SubFigure:kwdoc)s + """ + 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) - def clf(self, keep_observers=False): + @property + def canvas(self): + return self._parent.canvas + + @property + def dpi(self): + return self._parent.dpi + + @dpi.setter + def dpi(self, value): + self._parent.dpi = value + + def get_dpi(self): """ - Clear the figure. + Return the resolution of the parent figure in dots-per-inch as a float. + """ + return self._parent.dpi - Set *keep_observers* to True if, for example, - a gui widget is tracking the axes in the figure. + def set_dpi(self, val): """ - self.suppressComposite = None - self.callbacks = cbook.CallbackRegistry() + Set the resolution of parent figure in dots-per-inch. - for ax in tuple(self.axes): # Iterate over the copy. - ax.cla() - self.delaxes(ax) # removes ax from self._axstack + Parameters + ---------- + val : float + """ + self._parent.dpi = val + self.stale = True - 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 + def _get_renderer(self): + return self._parent._get_renderer() + + def _redo_transform_rel_fig(self, bbox=None): + """ + Make the transSubfigure bbox relative to Figure transform. - def clear(self): + Parameters + ---------- + bbox : bbox or None + If not None, then the bbox is used for relative bounding box. + Otherwise, it is calculated from the subplotspec. """ - Clear the figure -- synonym for :meth:`clf`. + 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) + + def get_constrained_layout(self): """ - self.clf() + Return whether constrained layout is being used. - @allow_rasterization - def draw(self, renderer): + See :ref:`constrainedlayout_guide`. """ - Render the figure using :class:`matplotlib.backend_bases.RendererBase` - instance *renderer*. + return self._parent.get_constrained_layout() + + def get_constrained_layout_pads(self, relative=False): """ + 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. + """ + return self._parent.get_constrained_layout_pads(relative=relative) + + def get_layout_engine(self): + return self._parent.get_layout_engine() + + @property + def axes(self): + """ + 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') - # a list of (zorder, func_to_call, list_of_args) - dsu = [] + finally: + self.stale = False - for a in self.patches: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) - for a in self.lines: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) +@_docstring.interpd +class Figure(FigureBase): + """ + The top level container for all the plot elements. - for a in self.artists: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) + See `matplotlib.figure` for an index of class methods. - # 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 + Attributes + ---------- + patch + The `.Rectangle` instance representing the figure background patch. - 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] + 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. + """ - im = _image.from_images(int(self.bbox.height * mag), - int(self.bbox.width * mag), - ims) + # 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. - im.is_grayscale = False - l, b, w, h = self.bbox.bounds + _render_lock = threading.RLock() - 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 __str__(self): + return "Figure(%gx%g)" % tuple(self.bbox.size) - dsu.append((self.images[0].get_zorder(), self.images[0], - draw_composite, [])) + 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), + ) - # render the axes - for a in self.axes: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) + 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 - # render the figure text - for a in self.texts: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) + - 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")``. - for a in self.legends: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) + One of *width* or *height* may be ``None``; the respective value is + taken from :rc:`figure.figsize`. - 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) + 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') - renderer.close_group('figure') + 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) - self._cachedRenderer = 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 - self.canvas.draw_event(renderer) + 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) - 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._set_base_canvas() + + if subplotpars is None: + subplotpars = SubplotParams() + + self.subplotpars = subplotpars + + 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 a 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. + + Do not modify the list itself. Instead, use `~Figure.add_axes`, + `~.Figure.add_subplot` or `~.Figure.delaxes` to add or remove an Axes. - @docstring.dedent_interpd - def text(self, x, y, s, *args, **kwargs): + 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 - text(x, y, s, fontdict=None, **kwargs) + def _set_dpi(self, dpi, forward=True): + """ + Parameters + ---------- + dpi : float + + 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): """ - Get 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. + if isinstance(self.get_layout_engine(), ConstrainedLayoutEngine): + self.get_layout_engine().set(**kwargs) + + @_api.deprecated("3.6", alternative="fig.get_layout_engine().get()", + pending=True) + def get_constrained_layout_pads(self, relative=False): """ - # 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 + Get padding for ``constrained_layout``. - # 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 + 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. - 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) + See :ref:`constrainedlayout_guide`. - # add version information to the state - state['__mpl_version__'] = _mpl_version + 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'] - # 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 + 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 - return state + return w_pad, h_pad, wspace, hspace - def __setstate__(self, state): - version = state.pop('__mpl_version__') - restore_to_pylab = state.pop('_restore_to_pylab', False) + def _set_base_canvas(self): + """ + Initialize self.canvas with a FigureCanvasBase instance. - if version != _mpl_version: - import warnings - warnings.warn("This figure was saved with matplotlib version %s " - "and is unlikely to function correctly." % - (version, )) + This is used upon initialization of the Figure, but also + to reset the canvas when decoupling from pyplot. + """ + FigureCanvasBase(self) # Set self.canvas as a side-effect + # undo any high-dpi scaling + if self._dpi != self._original_dpi: + self.dpi = self._original_dpi - self.__dict__ = state + def set_canvas(self, canvas): + """ + Set the canvas that contains the figure - # re-initialise some of the unstored state information - self._axobservers = [] - self.canvas = None + Parameters + ---------- + canvas : FigureCanvas + """ + self.canvas = canvas - 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) + @_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. - # XXX The following is a copy and paste from pyplot. Consider - # factoring to pylab_helpers + The image is attached to the lower or upper left corner depending on + *origin*. - if self.get_label(): - mgr.set_window_title(self.get_label()) + Parameters + ---------- + X + The image data. This is an array of one of the following shapes: - # make this figure current on button press event - def make_active(event): - pylab_helpers.Gcf.set_active(mgr) + - (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. - mgr._cidgcf = mgr.canvas.mpl_connect('button_press_event', - make_active) + xo, yo : int + The *x*/*y* image offset in pixels. - pylab_helpers.Gcf.set_active(mgr) - self.number = num + alpha : None or float + The alpha blending value. - plt.draw_if_interactive() + %(cmap_doc)s - def add_axobserver(self, func): - 'whenever the axes state change, ``func(self)`` will be called' - self._axobservers.append(func) + This parameter is ignored if *X* is RGB(A). - def savefig(self, *args, **kwargs): - """ - Save the current figure. + %(norm_doc)s - Call signature:: + This parameter is ignored if *X* is RGB(A). - 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) + %(vmin_vmax_doc)s - The output formats available depend on the backend being used. + This parameter is ignored if *X* is RGB(A). - Arguments: + 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. - *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`. + resize : bool + If *True*, resize the figure to match the given image size. - 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. + %(colorizer_doc)s - If *fname* is not a string, remember to specify *format* to - ensure that the correct backend is used. + This parameter is ignored if *X* is RGB(A). - Keyword arguments: + Returns + ------- + `matplotlib.image.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. + Other Parameters + ---------------- + **kwargs + Additional kwargs are `.Artist` kwargs passed on to `.FigureImage`. - *facecolor*, *edgecolor*: - the colors of the figure rectangle + 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]. - *orientation*: [ 'landscape' | 'portrait' ] - not supported on all backends; currently only on postscript output + Examples + -------- + :: - *papertype*: - One of 'letter', 'legal', 'executive', 'ledger', 'a0' through - 'a10', 'b0' through 'b10'. Only supported for 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) - *format*: - One of the file extensions supported by the active - backend. Most backends support png, pdf, ps, eps and svg. + im = mimage.FigureImage(self, cmap=cmap, norm=norm, + colorizer=colorizer, + offsetx=xo, offsety=yo, + origin=origin, **kwargs) + im.stale_callback = _stale_figure_callback - *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. + 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 - *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. + def set_size_inches(self, w, h=None, forward=True): + """ + Set the figure size in inches. - *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. + Call signatures:: - *pad_inches*: - Amount of padding around the figure when bbox_inches is - 'tight'. + fig.set_size_inches(w, h) # OR + fig.set_size_inches((w, h)) - *bbox_extra_artists*: - A list of extra artists that will be considered when the - tight bbox is calculated. + 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. + + 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 + if w is None or h is None: + raise ValueError( + "Figure.set_size_inches does not accept None; provide both " + "width and height explicitly") + 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 + self._set_base_canvas() + # force the bounding boxes to respect current dpi + self.dpi_scale_trans.clear().scale(self._dpi) + 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() - def get_tightbbox(self, renderer): - """ - Return a (tight) bounding box of the figure in inches. + 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:: - if len(bb) == 0: - return self.bbox_inches + 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)) @@ -1740,4 +3750,60 @@ 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: + x, y = figsize + elif num_parts == 3: + x, y, unit = figsize + if unit == 'in': + pass + elif unit == 'cm': + if x is not None: + x /= 2.54 + if y is not None: + y /= 2.54 + elif unit == 'px': + if x is not None: + x /= dpi + if y is not None: + y /= dpi + else: + raise ValueError( + f"Invalid unit {unit!r} in 'figsize'; " + "supported units are 'in', 'cm', 'px'" + ) + else: + raise ValueError( + "Invalid figsize format, expected (x, y) or (x, y, unit) but got " + f"{figsize!r}" + ) + + if x is None and y is None: + raise ValueError( + "figsize=(None, None) is invalid; at least one of width or " + "height must be provided") + + default_width, default_height = mpl.rcParams["figure.figsize"] + if x is None: + x = default_width + if y is None: + y = default_height + return x, y diff --git a/lib/matplotlib/figure.pyi b/lib/matplotlib/figure.pyi new file mode 100644 index 000000000000..59d276362dc5 --- /dev/null +++ b/lib/matplotlib/figure.pyi @@ -0,0 +1,451 @@ +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, LegendLocType + +_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: Any, projection: Literal["3d"], **kwargs: Any) -> Axes3D: ... + @overload + def add_subplot( + self, nrows: int, ncols: int, index: int | tuple[int, int], **kwargs: Any + ) -> Axes: ... + @overload + def add_subplot(self, pos: int, **kwargs: Any) -> Axes: ... + @overload + def add_subplot(self, ax: Axes, **kwargs: Any) -> Axes: ... + @overload + def add_subplot(self, ax: SubplotSpec, **kwargs: Any) -> Axes: ... + @overload + def add_subplot(self, **kwargs: Any) -> 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], + *, loc: LegendLocType | None = ..., **kwargs) -> Legend: ... + @overload + def legend(self, *, handles: Iterable[Artist], + loc: LegendLocType | None = ..., **kwargs) -> Legend: ... + @overload + def legend(self, labels: Iterable[str], + *, loc: LegendLocType | None = ..., **kwargs) -> Legend: ... + @overload + def legend(self, *, loc: LegendLocType | None = ..., **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[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 02b020b58e08..000000000000 --- a/lib/matplotlib/finance.py +++ /dev/null @@ -1,1351 +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 warnings -from six.moves.urllib.request import urlopen - -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 - - -if six.PY3: - import hashlib - - def md5(x): - return hashlib.md5(x.encode()) -else: - from hashlib import md5 - -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)]) - - -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, - 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_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_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_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_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_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 67c06274628e..3146a484f0fe 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1,128 +1,151 @@ """ 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 -from collections import Iterable -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 dataclasses +from functools import cache, lru_cache +import functools +from io import BytesIO +import json +import logging +from numbers import Integral +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", @@ -132,289 +155,319 @@ "/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 and sys.platform != 'win32': - 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 _normalize_weight(weight): + return weight if isinstance(weight, Integral) else weight_dict[weight] + 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: - 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]): + 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: - 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 - - 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 + return items -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'): """ - Search for fonts in the specified font paths. If no paths are - given, will use a standard set of system paths, as well as the - list of fonts tracked by fontconfig if fontconfig is installed and - available. A list of TrueType fonts are returned by default with - AFM fonts as an option. + Find fonts in a search path, system paths, or some other platform-specific method. + + Parameters + ---------- + fontpaths : list of str, optional + Search for fonts in these specified font paths. If no paths are given and the + :envvar:`MPL_IGNORE_SYSTEM_FONTS` is not set, use a standard set of system + paths, as well as the list of fonts tracked by fontconfig if fontconfig is + installed and available. + fontext : {'ttf', 'afm'}, default: 'ttf' + If 'ttf', search for TrueType fonts; if 'afm', search for with AFM fonts. + + Returns + ------- + list of str + A list of file paths with fonts of the given type. """ - 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 + if os.getenv('MPL_IGNORE_SYSTEM_FONTS'): + installed_fonts = [] + fontpaths = [] + elif sys.platform == 'win32': + installed_fonts = _get_win32_installed_fonts() + fontpaths = [] + elif sys.platform == 'emscripten': + 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 + fontfiles.update(map(os.path.abspath, list_fonts(path, fontexts))) + + return [fname for fname in fontfiles if os.path.exists(fname)] - return [fname for fname in six.iterkeys(fontfiles) if os.path.exists(fname)] -def weight_as_number(weight): +# To maintain backwards-compatibility with the current code we need to continue to +# return a str. However to support indexing into the file we need to return both the +# path and the index. Thus, we sub-class str to maintain compatibility and extend it to +# carry the index. +# +# The other alternative would be to create a completely new API and deprecate the +# existing one. In this case, sub-classing str is the simpler and less-disruptive +# option. +class FontPath(str): """ - Return the weight property as a numeric value. String values - are converted to their corresponding numeric value. + A class to describe a path to a font with a face index. + + Parameters + ---------- + path : str + The path to a font. + face_index : int + The face index in the font. """ - 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 + __match_args__ = ('path', 'face_index') + + def __new__(cls, path, face_index): + ret = super().__new__(cls, path) + ret._face_index = face_index + return ret + + @property + def path(self): + """The path to a font.""" + return str(self) + + @property + def face_index(self): + """The face index in a font.""" + return self._face_index + + def _as_tuple(self): + return (self.path, self.face_index) + + def __eq__(self, other): + if isinstance(other, FontPath): + return self._as_tuple() == other._as_tuple() + return super().__eq__(other) + + def __ne__(self, other): + return not (self == other) + + def __lt__(self, other): + if isinstance(other, FontPath): + return self._as_tuple() < other._as_tuple() + return super().__lt__(other) -class FontEntry(object): + def __gt__(self, other): + return not (self == other or self < other) + + def __hash__(self): + return hash(self._as_tuple()) + + def __repr__(self): + return f'FontPath{self._as_tuple()}' + + +@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 = '' + index: int = 0 + 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 @@ -423,21 +476,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, @@ -446,12 +525,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' @@ -463,24 +541,105 @@ 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())) + if not font.scalable: + raise NotImplementedError("Non-scalable fonts are not supported") + size = 'scalable' - # !!!! Incomplete - size_adjust = None + return FontEntry(font.fname, font.face_index, name, + style, variant, weight, stretch, size) - return FontEntry(font.fname, name, style, variant, weight, stretch, size) + +def _get_font_alt_names(font, primary_name): + """ + Return ``(name, weight)`` pairs for alternate family names of *font*. + + A font file can advertise its family name in several places. FreeType + exposes ``font.family_name``, which is typically derived from the + Macintosh-platform Name ID 1 entry. However, other entries may carry + different (equally valid) names that users reasonably expect to work: + + - **Name ID 1, other platform** — some fonts store a different family name + on the Microsoft platform than on the Macintosh platform. + - **Name ID 16** — "Typographic Family" (a.k.a. preferred family): groups + more than the traditional four styles under one name. + - **Name ID 21** — "WWS Family": an even narrower grouping used by some + fonts (weight/width/slope only). + + Each name is paired with a weight derived from the corresponding subfamily + entry on the *same* platform. This ensures that the weight of the alternate entry + reflects the font's role *within that named family* rather than its absolute + typographic weight. + + Parameters + ---------- + font : `.FT2Font` + primary_name : str + The family name already extracted from the font (``font.family_name``). + + Returns + ------- + list of (str, int) + ``(alternate_family_name, weight)`` pairs, not including *primary_name*. + """ + try: + sfnt = font.get_sfnt() + except ValueError: + return [] + + 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 + + seen = {primary_name} + result = [] + + def _weight_from_subfam(subfam): + subfam = subfam.replace(" ", "") + for regex, weight in _weight_regexes: + if re.search(regex, subfam, re.I): + return weight + return 400 # "Regular" or unrecognised + + def _try_add(name, subfam): + name = name.strip() + if not name or name in seen: + return + seen.add(name) + result.append((name, _weight_from_subfam(subfam.strip()))) + + # Each family-name ID is paired with its corresponding subfamily ID on the + # same platform: (family_id, subfamily_id). + for fam_id, subfam_id in ((1, 2), (16, 17), (21, 22)): + _try_add( + sfnt.get((*mac_key, fam_id), b'').decode('latin-1'), + sfnt.get((*mac_key, subfam_id), b'').decode('latin-1'), + ) + _try_add( + sfnt.get((*ms_key, fam_id), b'').decode('utf-16-be'), + sfnt.get((*ms_key, subfam_id), b'').decode('utf-16-be'), + ) + + return result 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() @@ -488,9 +647,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' @@ -503,11 +662,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, @@ -515,12 +672,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' @@ -536,157 +692,133 @@ def afmFontProperty(fontpath, font): size = 'scalable' - # !!!! Incomplete - size_adjust = None - - return FontEntry(fontpath, name, style, variant, weight, stretch, size) + return FontEntry(fontpath, 0, 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 a single 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:: + + __init__(self, pattern=None, /, *, family=None, style=None, ...) + + plus a runtime check that pattern is not used alongside with the + keyword arguments. This results eventually in the two possible + call signatures:: - fontlist.append(prop) - return fontlist + FontProperties(pattern) + FontProperties(family=..., size=..., ...) -class FontProperties(object): + """ + @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: - - - 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`. + specification and *math_fontfamily* for math fonts: - - style: Either 'normal', 'italic' or 'oblique'. + - 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` - - variant: Either 'normal' or 'small-caps'. + - style: Either 'normal', 'italic' or 'oblique'. + Default: :rc:`font.style` - - 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' + - variant: Either 'normal' or 'small-caps'. + Default: :rc:`font.variant` - - 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' + - 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` - - 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 + - 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` - The default font property for TrueType fonts (as specified in the - default :file:`matplotlibrc` file) is:: + - 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` - sans-serif, normal, normal, normal, normal, scalable. + - 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` - 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. - Note that matplotlib's internal font manager and fontconfig use a + .. _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 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) @@ -694,75 +826,82 @@ 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()), - self.get_slant(), - self.get_variant(), - self.get_weight(), - self.get_stretch(), - self.get_size_in_points(), - self.get_file()) - return hash(l) + return hash(tuple(self.__dict__.values())) 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 + return list(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): """ - Set the font weight. Options are: A numeric value in the + Get the font weight. Options are: A numeric value in the range 0-1000 or one of 'light', 'normal', 'regular', 'book', '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): @@ -771,27 +910,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. @@ -800,109 +926,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`. - """ - if family is None: - family = rcParams['font.family'] - if is_string_like(family): - family = [six.text_type(family)] - elif (not is_string_like(family) and isinstance(family, Iterable)): - family = [six.text_type(f) for f in family] - self._family = family - set_name = set_family + :rc:`text.usetex` is `True`. Default: :rc:`font.family` + """ + family = mpl._val_or_rc(family, 'font.family') + if isinstance(family, str): + family = (family,) + self._family = tuple(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") - weight = weight_dict[weight] - 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: + try: + scale = font_scalings[size] + except KeyError as err: raise ValueError( - "Size is invalid. Valid font size are " + ", ".join( - str(i) for i in font_scalings.keys())) + "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): @@ -910,111 +1055,176 @@ 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): + # Bypass __init__ for speed, since values are already validated + new = FontProperties.__new__(FontProperties) + new.__dict__.update(self.__dict__) + return new + def copy(self): - """Return a deep copy of self""" - return FontProperties(_init = self) + """Return a copy of self.""" + return self.__copy__() -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 -def pickle_load(filename): + +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 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.0a4' def __init__(self, size=None, weight='normal'): self._version = self.__version__ @@ -1022,48 +1232,87 @@ 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. + try: + timer = threading.Timer(5, lambda: _log.warning( + 'Matplotlib is building the font cache; this may take a moment.')) + timer.start() + except RuntimeError: + timer = None + 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: + if timer: + 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) + for alt_name, alt_weight in _get_font_alt_names(font, prop.name): + self.ttflist.append( + dataclasses.replace(prop, name=alt_name, weight=alt_weight)) + + for face_index in range(1, font.num_faces): + subfont = ft2font.FT2Font(path, face_index=face_index) + prop = ttfFontProperty(subfont) + self.ttflist.append(prop) + for alt_name, alt_weight in _get_font_alt_names(subfont, prop.name): + self.ttflist.append( + dataclasses.replace(prop, name=alt_name, weight=alt_weight)) + + 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): """ @@ -1076,7 +1325,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): """ @@ -1084,50 +1333,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. @@ -1137,14 +1383,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. """ @@ -1155,7 +1401,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 @@ -1173,25 +1419,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 = _normalize_weight(weight1) + w2 = _normalize_weight(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. @@ -1206,44 +1452,187 @@ 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. + If :envvar:`MPL_IGNORE_SYSTEM_FONTS` is set, then this defaults to + Matplotlib's internal font directory. + + 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 + ------- + FontPath + 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 + """ + # 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 = [mpl.rcParams[f"font.{key}"] for key in [ + "family", "style", "variant", "weight", "stretch", "size", + "serif", "sans-serif", "cursive", "fantasy", "monospace"]] + rc_params = tuple(tuple(e) if isinstance(e, list) else e + for e in rc_params) # Make this hashable. + if directory is None and os.getenv('MPL_IGNORE_SYSTEM_FONTS'): + directory = cbook._get_data_path('fonts') + 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[FontPath] + 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. """ - if not isinstance(prop, FontProperties): - prop = FontProperties(prop) + + 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': @@ -1251,175 +1640,214 @@ 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 if score == 0: break + if best_font is not None and (_normalize_weight(prop.get_weight()) != + _normalize_weight(best_font.weight)): + _log.warning('findfont: Failed to find font weight %s, now using %s.', + prop.get_weight(), best_font.weight) 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 FontPath(_cached_realpath(result), best_font.index) -_is_opentype_cff_font_cache = {} +@_api.deprecated("3.11") 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, *, _kerning_factor, thread_id, + enable_last_resort): + (first_fontpath, first_fontindex), *rest = font_filepaths + fallback_list = [ + ft2font.FT2Font(fpath, face_index=index, + _kerning_factor=_kerning_factor) + for fpath, index 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, 0)) + 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, + _kerning_factor=_kerning_factor, + _warn_if_used=True)) + last_resort_index = len(fallback_list) + font = ft2font.FT2Font( + first_fontpath, face_index=first_fontindex, + _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) + + +@_api.delete_parameter('3.11', 'hinting_factor') +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, bytes, os.PathLike, FontPath], \ +str, bytes, os.PathLike, FontPath + 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() - else: - _rebuild() + If a single string, bytes, or `os.PathLike`, 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` - def findfont(prop, **kw): - global fontManager - font = fontManager.findfont(prop, **kw) - return font + """ + match font_filepaths: + case FontPath(path, index): + paths = ((_cached_realpath(path), index), ) + case str() | bytes() | os.PathLike() as path: + paths = ((_cached_realpath(path), 0), ) + case _: + paths = tuple( + (_cached_realpath(fname.path), fname.face_index) + if isinstance(fname, FontPath) else (_cached_realpath(fname), 0) + for fname in font_filepaths) + + font = _get_font( + # must be a tuple to be cached + paths, + _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'], + ) + # Ensure the transform is always consistent. + font._set_transform([[0x10000, 0], [0, 0x10000]], [0, 0]) + 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..4bb1a8bae2a9 --- /dev/null +++ b/lib/matplotlib/font_manager.pyi @@ -0,0 +1,164 @@ +from collections.abc import Iterable +from dataclasses import dataclass +from numbers import Integral +import os +from pathlib import Path +from typing import Any, Final, Literal + +from matplotlib._afm import AFM +from matplotlib import ft2font + +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 _normalize_weight(weight: str | Integral) -> Integral: ... +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 _get_font_alt_names( + font: ft2font.FT2Font, primary_name: str +) -> list[tuple[str, int]]: ... +def findSystemFonts( + fontpaths: Iterable[str | os.PathLike] | None = ..., fontext: Literal['ttf', 'afm'] = ... +) -> list[str]: ... + +class FontPath(str): + __match_args__: Final[tuple[str, ...]] + def __new__(cls: type[str], path: str, face_index: int) -> FontPath: ... + @property + def path(self) -> str: ... + @property + def face_index(self) -> int: ... + def _as_tuple(self) -> tuple[str, int]: ... + def __eq__(self, other: Any) -> bool: ... + def __ne__(self, other: Any) -> bool: ... + def __lt__(self, other: Any) -> bool: ... + def __gt__(self, other: Any) -> bool: ... + def __hash__(self) -> int: ... + def __repr__(self) -> str: ... + +@dataclass +class FontEntry: + fname: str = ... + index: int = ... + 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 | None = ..., + math_fontfamily: str | None = ..., + ) -> None: ... + def __hash__(self) -> int: ... + def __copy__(self) -> FontProperties: ... + 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 | 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 | os.PathLike) -> None: ... +def json_load(filename: str | 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 | 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 | os.PathLike | None = ..., + fallback_to_default: bool = ..., + rebuild_if_missing: bool = ..., + ) -> FontPath: ... + def get_font_names(self) -> list[str]: ... + def _find_fonts_by_props( + self, + prop: str | FontProperties, + fontext: Literal["ttf", "afm"] = ..., + directory: str | os.PathLike | None = ..., + fallback_to_default: bool = ..., + rebuild_if_missing: bool = ..., + ) -> list[FontPath]: ... + +def is_opentype_cff_font(filename: str) -> bool: ... +def get_font( + font_filepaths: Iterable[str | bytes | os.PathLike | FontPath] | str | bytes | os.PathLike | FontPath, +) -> ft2font.FT2Font: ... + +fontManager: FontManager + +def findfont( + prop: str | FontProperties, + fontext: Literal["ttf", "afm"] = ..., + directory: str | os.PathLike | None = ..., + fallback_to_default: bool = ..., + rebuild_if_missing: bool = ..., +) -> FontPath: ... +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..f8057742b376 --- /dev/null +++ b/lib/matplotlib/ft2font.pyi @@ -0,0 +1,375 @@ +from enum import Enum, Flag +from os import PathLike +import sys +from typing import BinaryIO, Literal, NewType, NotRequired, TypeAlias, TypedDict, cast, final, overload +from typing_extensions import Buffer # < Py 3.12 + +import numpy as np +from numpy.typing import NDArray + +__freetype_build_type__: str +__freetype_version__: str +__libraqm_version__: str + +# We can't change the type hints for standard library chr/ord, so character codes are a +# simple type alias. +CharacterCodeType: TypeAlias = int +# But glyph indices are internal, so use a distinct type hint. +GlyphIndexType = NewType('GlyphIndexType', int) + +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 RenderMode(Enum): + NORMAL = cast(int, ...) + LIGHT = cast(int, ...) + MONO = cast(int, ...) + LCD = cast(int, ...) + LCD_V = cast(int, ...) + SDF = 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 + ulUnicodeRange: tuple[int, int, int, int] + achVendID: bytes + fsSelection: int + usFirstCharIndex: int + usLastCharIndex: int + sTypoAscender: int + sTypoDescender: int + sTypoLineGap: int + usWinAscent: int + usWinDescent: int + # version >= 1 + ulCodePageRange: NotRequired[tuple[int, int]] + # version >= 2 + sxHeight: NotRequired[int] + sCapHeight: NotRequired[int] + usDefaultChar: NotRequired[int] + usBreakChar: NotRequired[int] + usMaxContext: NotRequired[int] + # version >= 5 + usLowerOpticalPointSize: NotRequired[int] + usUpperOpticalPointSize: NotRequired[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 + minBottomSideBearing: 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 LayoutItem: + @property + def ft_object(self) -> FT2Font: ... + @property + def char(self) -> str: ... + @property + def glyph_index(self) -> GlyphIndexType: ... + @property + def x(self) -> float: ... + @property + def y(self) -> float: ... + @property + def prev_kern(self) -> float: ... + def __str__(self) -> str: ... + +@final +class FT2Font(Buffer): + def __init__( + self, + filename: str | bytes | PathLike | BinaryIO, + *, + face_index: int = ..., + _fallback_list: list[FT2Font] | None = ..., + _kerning_factor: int | None = ..., + _warn_if_used: bool = ..., + ) -> None: ... + if sys.version_info[:2] >= (3, 12): + def __buffer__(self, /, flags: int) -> memoryview: ... + def _layout( + self, + text: str, + flags: LoadFlags, + features: tuple[str, ...] | None = ..., + language: str | tuple[tuple[str, int, int], ...] | None = ..., + ) -> list[LayoutItem]: ... + 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: CharacterCodeType) -> GlyphIndexType: ... + def get_charmap(self) -> dict[CharacterCodeType, GlyphIndexType]: ... + def get_descent(self) -> int: ... + def get_glyph_name(self, index: GlyphIndexType) -> str: ... + def get_image(self) -> NDArray[np.uint8]: ... + def get_kerning(self, left: GlyphIndexType, right: GlyphIndexType, mode: Kerning) -> int: ... + def get_name_index(self, name: str) -> GlyphIndexType: ... + 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: CharacterCodeType, flags: LoadFlags = ...) -> Glyph: ... + def load_glyph(self, glyphindex: GlyphIndexType, 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 = ..., + *, + features: tuple[str] | None = ..., + language: str | list[tuple[str, int, int]] | None = ..., + ) -> 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 face_index(self) -> int: ... + @property + def family_name(self) -> str: ... + @property + def fname(self) -> str | bytes: ... + @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..4feb90d34715 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.13', # 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 2428147218bb..25e6a3bd5ee8 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -1,462 +1,735 @@ """ The image module supports basic image loading, rescaling and display operations. - """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six 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() + + # When an output pixel falls exactly on the edge between two input pixels, the Agg + # resampler will use the right input pixel as the nearest neighbor. We want the + # left input pixel to be chosen instead, so we flip the input data and the supplied + # transform. If origin != 'upper', the transform will already include a flip in the + # vertical direction. + if interpolation == 'nearest': + transform = Affine2D().translate(-data.shape[1], 0).scale(-1, 1) + transform + data = np.flip(data, axis=1) + if image_obj.origin == 'upper': + transform = Affine2D().translate(0, -data.shape[0]).scale(1, -1) + transform + data = np.flip(data, axis=0) + + _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['_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 - - # 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) - - 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)) - 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 + 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.") + + clipped_bbox = Bbox.intersection(out_bbox, clip_bbox) + + if clipped_bbox is None: + return None, 0, 0, None + + # Define the magnified bbox after clipping + magnified_extents = clipped_bbox.extents * magnification + if ((not unsampled) and round_to_pixel_border): + # Round to the nearest output pixel + # Add a tiny fudge amount to account for numerical precision loss + # on the two sides away from the Agg anchor point (x0, y1) + x0 = np.floor(magnified_extents[0] + 0.5) # round half up + y0 = np.ceil(magnified_extents[1] - 0.5 - 1e-8) # round half down + x1 = np.floor(magnified_extents[2] + 0.5 + 1e-8) # round half up + y1 = np.ceil(magnified_extents[3] - 0.5) # round half down + magnified_bbox = Bbox.from_extents([x0, y0, x1, y1]) else: - yslice = slice(0, numrows) + magnified_bbox = Bbox.from_extents(magnified_extents) - if xslice != self._oldxslice or yslice != self._oldyslice: - self._imcache = None - self._oldxslice = xslice - self._oldyslice = yslice + if magnified_bbox.width == 0 or magnified_bbox.height == 0: + return None, 0, 0, None - if self._imcache is None: - A = self._A - if self.origin == 'upper': - A = A[::-1] - - 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 + 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() + .scale(magnification) + .translate(-magnified_bbox.x0, -magnified_bbox.y0))) + + out_shape = (int(magnified_bbox.height), int(magnified_bbox.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 + if A.shape[2] == 3: # RGB: use array alpha directly + A = np.dstack([A, alpha]) + else: # RGBA: multiply existing alpha by array alpha + A = np.dstack([A[..., :3], 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) - @staticmethod - def _get_rotate_and_skew_transform(x1, y1, x2, y2, x3, y3): + else: + if self._imcache is None: + self._imcache = self.to_rgba(A, bytes=True, norm=(A.ndim == 2)) + output = self._imcache + + # 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]))] + + t = Affine2D().translate( + int(max(subset.xmin, 0)), int(max(subset.ymin, 0))) + t + + return (output, + magnified_bbox.x0 / magnification, + magnified_bbox.y0 / magnification, + t) + + def make_image(self, renderer, magnification=1.0, unsampled=False): """ - 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). + 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. """ - 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]]) - - a, b = (inv_mat * np.mat([[x2a], [x2a]])).flat - c, d = (inv_mat * np.mat([[y2a], [0]])).flat - - tr2 = mtransforms.Affine2D.from_values(a, c, b, d, 0, 0) - - tr = (tr1 + tr2 + - mtransforms.Affine2D().translate(x1, y1)).inverted().get_affine() + raise NotImplementedError('The make_image method must be overridden') - return tr - - def _draw_unsampled_image(self, renderer, gc): - """ - draw unsampled image. The renderer should support a draw_image method - with scale parameter. + def _check_unsampled_image(self): """ - 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() + Return whether the image is better to be drawn unsampled. - 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): - """ - return True if 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 - - 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 @@ -464,215 +737,259 @@ 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. + + See help for `~.Axes.imshow`. - ACCEPTS: 0 or 1 + 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). - ACCEPTS: positive float + See help for `~.Axes.imshow`. + + 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 - ) + 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.axes.transData) - - 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') + 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): - """ - return True if the image is better to be drawn unsampled. + 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): """ - 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): + 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`. """ - extent is data axes (left, right, bottom, top) for making image plots - - 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. + (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] - """ self._extent = extent - - xmin, xmax, ymin, ymax = extent corners = (xmin, ymin), (xmax, ymax) self.axes.update_datalim(corners) - if self.axes._autoscaleXon: - self.axes.set_xlim((xmin, xmax), auto=None) - if self.axes._autoscaleYon: - self.axes.set_ylim((ymin, ymax), auto=None) + 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.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: @@ -683,762 +1000,854 @@ def get_extent(self): 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] + - def _check_unsampled_image(self, renderer): +class NonUniformImage(AxesImage): + """ + An image with pixels on a rectilinear grid. + + 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 + magnified_extents = (self.axes.bbox.extents * magnification + 0.5).astype(int) + l, b, r, t = magnified_extents / magnification + width = int((r - l) * magnification) + height = int((t - b) * magnification) + + invertedTransform = self.axes.transData.inverted() + x_pix_edges = invertedTransform.transform( + [(x, b) for x in np.linspace(l, r, width + 1)])[:, 0] + y_pix_edges = invertedTransform.transform( + [(l, y) for y in np.linspace(b, t, height + 1)])[:, 1] + x_pix_centers = (x_pix_edges[:-1] + x_pix_edges[1:]) / 2 + y_pix_centers = (y_pix_edges[:-1] + y_pix_edges[1:]) / 2 + + 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_centers) + y_int = y_mid.searchsorted(y_pix_centers) + # 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_centers) - 1, 0, len(self._Ax) - 2) + y_int = np.clip( + self._Ay.searchsorted(y_pix_centers) - 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_centers - 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_centers - 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) - 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: + if unsampled: + raise ValueError('unsampled not supported on PColorImage') + + if self._imcache 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 - 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 + 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 + + # Round to the nearest output pixels after magnification + l, b, r, t = (self.axes.bbox.extents * magnification + 0.5).astype(int) + width = r - l + height = t - b - def changed(self): - self._rgbacache = None - cm.ScalarMappable.changed(self) + vl = self.axes.viewLim - @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_edges = np.linspace(vl.x0, vl.x1, width + 1) + y_pix_edges = np.linspace(vl.y0, vl.y1, height + 1) + x_pix_centers = (x_pix_edges[:-1] + x_pix_edges[1:]) / 2 + y_pix_centers = (y_pix_edges[:-1] + y_pix_edges[1:]) / 2 + x_int = self._Ax.searchsorted(x_pix_centers) + y_int = self._Ay.searchsorted(y_pix_centers) + 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 / magnification, b / magnification, 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 - - 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)) + super().set_data(A) + self.stale = True - 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] - - x = self.to_rgba(A, bytes=True) - self.magnification = magnification - # if magnification is not one, we need to resize - ismag = magnification != 1 - 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. This parameter is ignored if X is RGB(A). + norm : str or `~matplotlib.colors.Normalize` + Maps luminance to 0-1. This parameter is ignored if X is RGB(A). + 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, ry) - 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()) - - 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))) - 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 `Pillow for a replacement + `_. + 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', + 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..aae640db6f81 --- /dev/null +++ b/lib/matplotlib/inset.py @@ -0,0 +1,290 @@ +""" +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. + + Parameters + ---------- + ls : {'-', '--', '-.', ':', '', ...} or (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 + ======================================================= ================ + + - A tuple describing the start position and lengths of dashes and spaces: + + (offset, onoffseq) + + where + + - *offset* is a float specifying the offset (in points); i.e. how much + is the dash pattern shifted. + - *onoffseq* is a sequence of on and off ink in points. There can be + arbitrary many pairs of on and off values. + + Example: The tuple ``(0, (10, 5, 1, 5))`` means that the pattern starts + at the beginning of the line. It draws a 10 point long dash, + then a 5 point long space, then a 1 point long dash, followed by a 5 point + long space, and then the pattern repeats. + + For examples see :doc:`/gallery/lines_bars_and_markers/linestyles`. + """ + 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 c7423fb4518c..e25c3525821c 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -1,51 +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) +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, PatchCollection, 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 @@ -53,236 +54,436 @@ 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*. + This is an advanced option for free placement of the legend. For + most use cases, *loc* alone is sufficient. + + Defaults to ``axes.bbox`` (if called as a method to `.Axes.legend`) or + ``figure.bbox`` (if ``figure.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) + + For more details on legend positioning, see the + :ref:`legend_guide`. + +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`. + +linewidth : float or None, default: :rc:`legend.linewidth` + The legend's background patch edge linewidth. + If ``None``, use :rc:`patch.linewidth`. + + .. versionadded:: 3.11 + +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 string locations place the legend at the corresponding position + within the bounding box, which by default is the full {parent} area. + The bounding box can be changed via *bbox_to_anchor*. + + The positions are visualized below:: + + +--------------+--------------+---------------+ + | 'upper left' |'upper center'| 'upper right' | + +--------------+--------------+---------------+ + |'center left' | 'center' |'center right' | + +--------------+--------------+---------------+ + | 'lower left' |'lower center'| 'lower right' | + +--------------+--------------+---------------+ +{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 currently takes into account most, but not all, artists + added to the Axes via plotting functions. In particular it does not consider + inset axes, titles, or axis labels. + + The computation of the best position can be expensive for plots with large + amounts of data. If speed becomes a concern, you may 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 + linewidth=None, # frame patch linewidth + + 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) @@ -292,11 +493,11 @@ 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 @@ -304,152 +505,275 @@ def __init__(self, parent, handles, labels, if isinstance(parent, Axes): self.isaxes = True self.axes = parent - self.set_figure(parent.figure) - elif isinstance(parent, Figure): + 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") + linewidth = mpl._val_or_rc(linewidth, "legend.linewidth") + + self.legendPatch = FancyBboxPatch( + xy=(0, 0), width=1, height=1, + facecolor=facecolor, edgecolor=edgecolor, + linewidth=linewidth, + # 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_markerfacecolor', + 'get_facecolor', + 'get_markeredgecolor', + 'get_edgecolor', + 'get_color'], + '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)() + except AttributeError: + continue + if isinstance(color, np.ndarray): + if color.size == 0: + continue + elif (color.shape[0] == 1 or np.isclose(color, color[0]).all()): + text.set_color(color[0]) + else: + pass + elif cbook._str_lower_equal(color, 'none'): + continue + elif mpl.colors.to_rgba(color)[3] == 0: + continue + else: + text.set_color(color) + break + 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.getitem_checked(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 + self.stale = True + self._legend_box.set_offset(self._findoffset) -# def findoffset(width, height, xdescent, ydescent): -# return _findoffset(width, height, xdescent, ydescent, renderer) - - 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_loc(self, width, height, xdescent, ydescent, renderer): - "Helper function to locate the legend using the location code" + def _findoffset(self, width, height, xdescent, ydescent, renderer): + """Helper function to locate the legend.""" - 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) @@ -457,30 +781,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. @@ -490,12 +804,14 @@ 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(), BarContainer: legend_handler.HandlerPatch( update_func=legend_handler.update_from_first_child), tuple: legend_handler.HandlerTuple(), + PatchCollection: legend_handler.HandlerPolyCollection(), PathCollection: legend_handler.HandlerPathCollection(), PolyCollection: legend_handler.HandlerPolyCollection() } @@ -505,67 +821,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): """ @@ -577,120 +876,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) + 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", @@ -699,131 +958,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 legend title. Fontproperties can be optionally set - with *prop* parameter. + 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'}. + """ - self._legend_title_box._text.set_text(title) + _api.check_in_list(["center", "left", "right"], alignment=alignment) + self._alignment = alignment + self._legend_box.align = alignment - if prop is not None: - if isinstance(prop, dict): - prop = FontProperties(**prop) - self._legend_title_box._text.set_fontproperties(prop) + def get_alignment(self): + """Get the alignment value of the legend box""" + return self._legend_box.align + + def set_title(self, title, prop=None): + """ + Set legend title and title style. + 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: @@ -831,12 +1116,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 @@ -846,8 +1142,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] @@ -859,129 +1155,92 @@ 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] + pad = self.borderaxespad * renderer.points_to_pixels(self._fontsize) + return offsetbox._get_anchored_bbox( + loc, bbox, parentbbox, + pad, pad) - 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, @@ -991,5 +1250,157 @@ 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 is not None and labels is not None: + 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] + 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)}") + + 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..e17738c76161 --- /dev/null +++ b/lib/matplotlib/legend.pyi @@ -0,0 +1,154 @@ +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, +) +from matplotlib.typing import ColorType, LegendLocType + + +import pathlib +from collections.abc import Iterable +from typing import Any, Literal, overload + + +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: LegendLocType | 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 = ..., + linewidth: float | 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: LegendLocType | 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..65a78891b17f 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,39 @@ 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 3c0c39153118..2c92b099099e 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 an 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,110 +469,133 @@ 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. - - e.g., if `every=5`, every 5-th marker will be plotted. + """ + Set the markevery property to subsample the plot when using markers. - ACCEPTS: [None | int | length-2 tuple of int | slice | - list/array of int | float | length-2 tuple of float] + 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 along the drawn line to the nearest + available data point. Depending on the number and distribution of data + points, and on how jagged the line is, the result may still not look + evenly spaced along the x- or y-axis. 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 @@ -509,56 +607,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 - @Artist.axes.setter - def axes(self, ax): - # call the set method from the base-class property - Artist.axes.fset(self, ax) - # connect unit-related callbacks - 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) - 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 @@ -571,98 +675,87 @@ 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._xy[:, 0] # views of the x and y data + self._y = self._xy[:, 1] 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) + if self._drawstyle == 'default': + vertices = self._xy + else: + step_func = STEP_LOOKUP_MAP[self._drawstyle] + vertices = np.asarray(step_func(*self._xy.T)).T + self._path = Path(vertices, _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, :]) + if self._drawstyle == 'default': + vertices = self._xy[subslice] + else: + step_func = STEP_LOOKUP_MAP[self._drawstyle] + vertices = np.asarray(step_func(*self._xy[subslice, :].T)).T + _path = Path(vertices, + _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 @@ -670,78 +763,117 @@ 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) - - ln_color_rgba = self._get_rgba_ln_color() - gc.set_foreground(ln_color_rgba, isRGBA=True) - gc.set_alpha(ln_color_rgba[3]) + 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()) - 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()) - - 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()) + 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()) + + # We first draw a path within the gaps if needed, but only for + # visible dashed lines; zero-width lines would otherwise yield + # all-zero dashes. + if (self._linewidth > 0 and 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) + + 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) + + if self._linewidth > 0: + gc.set_dashes(*self._dash_pattern) + else: + gc.set_dashes(0, None) + renderer.draw_path(gc, tpath, affine.frozen()) + gc.restore() - if self._marker: + 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()) @@ -749,93 +881,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. """ @@ -868,466 +1050,615 @@ 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. + + The drawstyle determines how the points are connected. + + Parameters + ---------- + drawstyle : {'default', 'steps', 'steps-pre', 'steps-mid', \ +'steps-post'}, default: 'default' + For 'default', the points are connected with straight lines. + + 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: - 'default' connects the points with lines. The steps variants - produce step-plots. 'steps' is equivalent to 'steps-pre' and - is maintained for backward-compatibility. + - '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. - ACCEPTS: ['default' | 'steps' | 'steps-pre' | 'steps-mid' | - 'steps-post'] + For examples see :doc:`/gallery/lines_bars_and_markers/step_demo`. """ + 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. + + .. 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 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 + def set_linewidth(self, w): """ - Set the line width in points + Set the line width in points. - ACCEPTS: float value in points + 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) - def set_linestyle(self, linestyle): + def set_linestyle(self, ls): """ - Set the linestyle of the line (also accepts drawstyles) + Set the linestyle of the line. + Parameters + ---------- + ls : {'-', '--', '-.', ':', '', ...} or (offset, on-off-seq) + Possible values: - ================ ================= - linestyle description - ================ ================= - ``'-'`` solid - ``'--'`` dashed - ``'-.'`` dash_dot - ``':'`` dotted - ``'None'`` draw nothing - ``' '`` draw nothing - ``''`` draw nothing - ================ ================= + - A string: - 'steps' is equivalent to 'steps-pre' and is maintained for - backward-compatibility. + ======================================================= ================ + 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 + ======================================================= ================ - .. seealso:: + - A tuple describing the start position and lengths of dashes and spaces: - :meth:`set_drawstyle` - To set the drawing style (stepping) of the plot. + (offset, onoffseq) - ACCEPTS: [``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'None'`` | - ``' '`` | ``''``] + where - and any drawstyle in combination with a linestyle, e.g., ``'steps--'``. - """ + - *offset* is a float specifying the offset (in points); i.e. how much + is the dash pattern shifted. + - *onoffseq* is a sequence of on and off ink in points. There can be + arbitrary many pairs of on and off values. - 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 + Example: The tuple ``(0, (10, 5, 1, 5))`` means that the pattern starts + at the beginning of the line. It draws a 10 point long dash, + then a 5 point long space, then a 1 point long dash, followed by a 5 point + long space, and then the pattern repeats. - 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 + See also :meth:`set_dashes`. - @docstring.dedent_interpd - def set_marker(self, marker): + For examples see :doc:`/gallery/lines_bars_and_markers/linestyles`. """ - Set the line marker + 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 - ACCEPTS: :mod:`A valid marker style ` + @_docstring.interpd + def set_marker(self, 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 + Set the marker edge color. - ACCEPTS: any matplotlib color - """ - if ec is None: - ec = 'auto' - self._markeredgecolor = ec - - 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. + + Parameters + ---------- + y : 1D array - ACCEPTS: 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. - ACCEPTS: sequence of on/off ink in points + The dash sequence is a sequence of floats of even length describing + the length of dashes and spaces 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): + See also `~.Line2D.set_dash_capstyle`. """ - Get the join style for dashed linestyles - """ - 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 @@ -1335,66 +1666,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]) @@ -1403,9 +1729,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..52fa0797536a 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 Hashable, 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, Hashable) 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 9f975bda9312..42d4b5ef1fa8 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_rect_filled` - - :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_rect_filled(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 + max(d, 0))) - - 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.getitem_checked( + {"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.getitem_checked( + 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..c0bfdb227e2e --- /dev/null +++ b/lib/matplotlib/meson.build @@ -0,0 +1,170 @@ +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', + '_style_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 af2aba90e86f..a694308384c1 100644 --- a/lib/matplotlib/mlab.py +++ b/lib/matplotlib/mlab.py @@ -1,512 +1,197 @@ """ +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() - - """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import map, xrange, zip - -import copy -import csv -import operator -import os -import warnings +import functools +from numbers import Integral, Number +import sys import numpy as np -from matplotlib import verbose - -import matplotlib.cbook as cbook -from matplotlib import docstring -from matplotlib.path import Path -import math - -ma = np.ma - -if six.PY3: - long = int - - -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) @@ -517,7 +202,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] @@ -526,139 +211,22 @@ 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') - +def _stride_windows(x, n, noverlap=0): + _api.check_isinstance(Integral, n=n, noverlap=noverlap) 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') - - # np.lib.stride_tricks.as_strided easily leads to memory corruption for - # non integer shape and strides, i.e. noverlap or n. See #3845. - noverlap = int(noverlap) - n = int(n) - 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') - - # np.lib.stride_tricks.as_strided easily leads to memory corruption for - # non integer shape and strides, i.e. n. See #3845. - n = int(n) - - if axis == 0: - shape = (n, x.size) - strides = (0, x.strides[0]) - else: - shape = (x.size, n) - strides = (x.strides[0], 0) - + shape = (n, (x.shape[-1]-noverlap)//step) + strides = (x.strides[0], step*x.strides[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 @@ -681,12 +249,14 @@ def _spectral_helper(x, y=None, NFFT=None, Fs=None, detrend_func=None, if NFFT is None: NFFT = 256 + if not (0 <= 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'") @@ -702,19 +272,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: @@ -740,53 +308,78 @@ 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") + + if sys.maxsize > 2**32: + result = np.lib.stride_tricks.sliding_window_view( + x, NFFT, axis=0)[::NFFT - noverlap].T + else: + # The NumPy version on 32-bit will OOM, so use old implementation. + result = _stride_windows(x, NFFT, noverlap=noverlap) 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) + if sys.maxsize > 2**32: + resultY = np.lib.stride_tricks.sliding_window_view( + y, NFFT, axis=0)[::NFFT - noverlap].T + else: + # The NumPy version on 32-bit will OOM, so use old implementation. + resultY = _stride_windows(y, NFFT, noverlap=noverlap) 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 an 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 @@ -798,16 +391,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) @@ -821,104 +411,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 @@ -928,42 +491,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, @@ -971,18 +532,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 @@ -995,34 +550,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 @@ -1032,7 +588,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: @@ -1040,2641 +596,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) - - -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 - - -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. - -""" - - -# ***************************************************************************** -# 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. @@ -3686,24 +834,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(). @@ -3720,9 +866,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)) @@ -3735,7 +880,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 ---------- @@ -3745,7 +891,7 @@ def evaluate(self, points): Returns ------- - values : (# of points,)-array + (# of points,)-array The values at each point. Raises @@ -3758,11 +904,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 @@ -3784,266 +929,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 - """ - mask = np.asarray(mask, dtype=bool) - - if not mask.size: - return [] - - # Find the indices of region changes, and correct offset - idx, = np.nonzero(mask[:-1] != mask[1:]) - idx += 1 - - # 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)) - - return list(zip(idx[::2], idx[1::2])) - - -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. - """ - # TODO: Candidate for deprecation -- no longer used internally - - # 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/afm/cmti10.afm b/lib/matplotlib/mpl-data/fonts/afm/cmti10.afm new file mode 100644 index 000000000000..ac9e89f676b8 --- /dev/null +++ b/lib/matplotlib/mpl-data/fonts/afm/cmti10.afm @@ -0,0 +1,333 @@ +StartFontMetrics 2.0 +FontName cmti10 +FullName cmti10 +FamilyName cmti10 +Weight Medium +ItalicAngle 0.000000 +IsFixedPitch false +UnderlinePosition -133 +UnderlineThickness 20 +Version 1.1/12-Nov-94 +FontBBox -35, -250, 1125, 750 +Notice Copyright \(C\) 1994, Basil K. Malyshev. All Rights Reserved.\nBaKoMa Fonts Collection, Level-B. +EncodingScheme FontSpecific +CapHeight 683 +XHeight 431 +Descender -194 +Ascender 694 +StartCharMetrics 129 +C 0 ; WX 627.22 ; N Gamma ; B 59 0 706 683 ; +C 1 ; WX 817.78 ; N Delta ; B 70 0 752 716 ; +C 2 ; WX 766.67 ; N Theta ; B 148 -22 788 705 ; +C 3 ; WX 692.22 ; N Lambda ; B 58 0 643 716 ; +C 4 ; WX 664.44 ; N Xi ; B 75 0 755 683 ; +C 5 ; WX 743.33 ; N Pi ; B 59 0 854 683 ; +C 6 ; WX 715.56 ; N Sigma ; B 80 0 782 683 ; +C 7 ; WX 766.67 ; N Upsilon ; B 213 0 833 705 ; +C 8 ; WX 715.56 ; N Phi ; B 158 0 729 683 ; +C 9 ; WX 766.67 ; N Psi ; B 211 0 825 683 ; +C 10 ; WX 715.56 ; N Omega ; B 100 0 759 705 ; +C 11 ; WX 613.33 ; N ff ; B -25 -205 758 705 ; L i ffi ; L l ffl ; +C 12 ; WX 562.22 ; N fi ; B -25 -205 597 705 ; +C 13 ; WX 587.78 ; N fl ; B -25 -205 639 705 ; +C 14 ; WX 881.67 ; N ffi ; B -25 -205 917 705 ; +C 15 ; WX 894.44 ; N ffl ; B -25 -205 945 705 ; +C 16 ; WX 306.67 ; N dotlessi ; B 81 -11 334 442 ; +C 17 ; WX 332.22 ; N dotlessj ; B -35 -205 322 442 ; +C 18 ; WX 511.11 ; N grave ; B 291 503 433 696 ; +C 19 ; WX 511.11 ; N acute ; B 339 503 551 696 ; +C 20 ; WX 511.11 ; N caron ; B 279 505 538 633 ; +C 21 ; WX 511.11 ; N breve ; B 280 521 567 694 ; +C 22 ; WX 511.11 ; N macron ; B 232 555 566 589 ; +C 23 ; WX 831.28 ; N ring ; B 476 541 670 716 ; +C 24 ; WX 460 ; N cedilla ; B 99 -194 338 0 ; +C 25 ; WX 536.67 ; N germandbls ; B -20 -205 578 705 ; +C 26 ; WX 715.56 ; N ae ; B 90 -11 721 442 ; +C 27 ; WX 715.56 ; N oe ; B 106 -15 721 446 ; +C 28 ; WX 511.11 ; N oslash ; B 66 -109 553 540 ; +C 29 ; WX 882.78 ; N AE ; B 59 0 949 683 ; +C 30 ; WX 985 ; N OE ; B 162 -22 1051 705 ; +C 31 ; WX 766.67 ; N Oslash ; B 120 -62 818 745 ; +C 32 ; WX 255.56 ; N polishlcross ; B 91 280 345 393 ; +C 33 ; WX 306.67 ; N exclam ; B 111 0 376 716 ; L quoteleft exclamdown ; +C 34 ; WX 514.44 ; N quotedblright ; B 176 390 520 694 ; +C 35 ; WX 817.78 ; N numbersign ; B 115 -194 828 694 ; +C 36 ; WX 769.11 ; N dollar ; B 88 -11 698 709 ; +C 37 ; WX 817.78 ; N percent ; B 145 -56 847 750 ; +C 38 ; WX 766.67 ; N ampersand ; B 127 -22 803 716 ; +C 39 ; WX 306.67 ; N quoteright ; B 218 390 375 694 ; L quoteright quotedblright ; +C 40 ; WX 408.89 ; N parenleft ; B 150 -250 517 750 ; +C 41 ; WX 408.89 ; N parenright ; B 17 -250 384 750 ; +C 42 ; WX 511.11 ; N asterisk ; B 195 319 584 750 ; +C 43 ; WX 766.67 ; N plus ; B 140 -57 753 557 ; +C 44 ; WX 306.67 ; N comma ; B 72 -194 226 110 ; +C 45 ; WX 357.78 ; N hyphen ; B 85 185 340 245 ; L hyphen endash ; +C 46 ; WX 306.67 ; N period ; B 111 0 224 110 ; +C 47 ; WX 511.11 ; N slash ; B 20 -250 617 750 ; +C 48 ; WX 511.11 ; N zero ; B 115 -22 556 666 ; +C 49 ; WX 511.11 ; N one ; B 115 0 463 666 ; +C 50 ; WX 511.11 ; N two ; B 82 -22 551 666 ; +C 51 ; WX 511.11 ; N three ; B 95 -22 562 666 ; +C 52 ; WX 511.11 ; N four ; B 44 -194 475 666 ; +C 53 ; WX 511.11 ; N five ; B 107 -22 567 666 ; +C 54 ; WX 511.11 ; N six ; B 120 -22 567 666 ; +C 55 ; WX 511.11 ; N seven ; B 142 -22 628 666 ; +C 56 ; WX 511.11 ; N eight ; B 97 -22 554 666 ; +C 57 ; WX 511.11 ; N nine ; B 105 -22 553 666 ; +C 58 ; WX 306.67 ; N colon ; B 111 0 305 431 ; +C 59 ; WX 306.67 ; N semicolon ; B 72 -194 305 431 ; +C 60 ; WX 306.67 ; N exclamdown ; B 57 -216 322 500 ; +C 61 ; WX 766.67 ; N equal ; B 115 133 776 367 ; +C 62 ; WX 511.11 ; N questiondown ; B 85 -216 442 500 ; +C 63 ; WX 511.11 ; N question ; B 194 0 551 716 ; L quoteleft questiondown ; +C 64 ; WX 766.67 ; N at ; B 151 -11 789 705 ; +C 65 ; WX 743.33 ; N A ; B 58 0 693 716 ; +C 66 ; WX 703.89 ; N B ; B 62 0 734 683 ; +C 67 ; WX 715.56 ; N C ; B 150 -22 813 705 ; +C 68 ; WX 755 ; N D ; B 60 0 775 683 ; +C 69 ; WX 678.33 ; N E ; B 59 0 744 683 ; +C 70 ; WX 652.78 ; N F ; B 59 0 732 683 ; +C 71 ; WX 773.61 ; N G ; B 150 -22 813 705 ; +C 72 ; WX 743.33 ; N H ; B 59 0 854 683 ; +C 73 ; WX 385.56 ; N I ; B 55 0 503 683 ; +C 74 ; WX 525 ; N J ; B 90 -22 622 683 ; +C 75 ; WX 768.89 ; N K ; B 59 0 860 683 ; +C 76 ; WX 627.22 ; N L ; B 59 0 626 683 ; +C 77 ; WX 896.67 ; N M ; B 63 0 1004 683 ; +C 78 ; WX 743.33 ; N N ; B 59 0 854 683 ; +C 79 ; WX 766.67 ; N O ; B 148 -22 788 705 ; +C 80 ; WX 678.33 ; N P ; B 60 0 730 683 ; +C 81 ; WX 766.67 ; N Q ; B 148 -194 788 705 ; +C 82 ; WX 729.44 ; N R ; B 60 -22 723 683 ; +C 83 ; WX 562.22 ; N S ; B 74 -22 633 705 ; +C 84 ; WX 715.56 ; N T ; B 175 0 808 683 ; +C 85 ; WX 743.33 ; N U ; B 200 -22 854 683 ; +C 86 ; WX 743.33 ; N V ; B 208 -22 868 683 ; +C 87 ; WX 998.89 ; N W ; B 207 -22 1125 683 ; +C 88 ; WX 743.33 ; N X ; B 50 0 825 683 ; +C 89 ; WX 743.33 ; N Y ; B 201 0 875 683 ; +C 90 ; WX 613.33 ; N Z ; B 79 0 704 683 ; +C 91 ; WX 306.67 ; N bracketleft ; B 73 -250 446 750 ; +C 92 ; WX 514.44 ; N quotedblleft ; B 265 390 609 694 ; +C 93 ; WX 306.67 ; N bracketright ; B -14 -250 359 750 ; +C 94 ; WX 511.11 ; N circumflex ; B 264 533 524 694 ; +C 95 ; WX 306.67 ; N dotaccent ; B 251 559 364 669 ; +C 96 ; WX 306.67 ; N quoteleft ; B 204 390 361 694 ; L quoteleft quotedblleft ; +C 97 ; WX 511.11 ; N a ; B 107 -11 538 442 ; +C 98 ; WX 460 ; N b ; B 113 -11 461 694 ; +C 99 ; WX 460 ; N c ; B 108 -11 470 442 ; +C 100 ; WX 511.11 ; N d ; B 107 -11 562 694 ; +C 101 ; WX 460 ; N e ; B 112 -11 468 442 ; +C 102 ; WX 306.67 ; N f ; B -25 -205 452 705 ; L i fi ; L f ff ; L l fl ; +C 103 ; WX 460 ; N g ; B 51 -205 489 442 ; +C 104 ; WX 511.11 ; N h ; B 74 -11 538 694 ; +C 105 ; WX 306.67 ; N i ; B 81 -11 334 656 ; +C 106 ; WX 306.67 ; N j ; B -35 -205 359 656 ; +C 107 ; WX 460 ; N k ; B 74 -11 501 694 ; +C 108 ; WX 255.56 ; N l ; B 92 -11 308 694 ; +C 109 ; WX 817.78 ; N m ; B 81 -11 845 442 ; +C 110 ; WX 562.22 ; N n ; B 81 -11 589 442 ; +C 111 ; WX 511.11 ; N o ; B 108 -11 511 442 ; +C 112 ; WX 511.11 ; N p ; B 12 -194 512 442 ; +C 113 ; WX 460 ; N q ; B 107 -194 499 442 ; +C 114 ; WX 421.67 ; N r ; B 81 -11 488 442 ; +C 115 ; WX 408.89 ; N s ; B 76 -11 419 442 ; +C 116 ; WX 332.22 ; N t ; B 90 -11 373 626 ; +C 117 ; WX 536.67 ; N u ; B 81 -11 564 442 ; +C 118 ; WX 460 ; N v ; B 81 -11 492 443 ; +C 119 ; WX 664.44 ; N w ; B 81 -11 696 443 ; +C 120 ; WX 463.89 ; N x ; B 55 -11 517 442 ; +C 121 ; WX 485.56 ; N y ; B 81 -205 517 442 ; +C 122 ; WX 408.89 ; N z ; B 60 -11 465 442 ; +C 123 ; WX 511.11 ; N endash ; B 92 253 552 279 ; L hyphen emdash ; +C 124 ; WX 1022.22 ; N emdash ; B 118 253 1037 279 ; +C 125 ; WX 511.11 ; N hungarumlaut ; B 267 505 576 697 ; +C 126 ; WX 511.11 ; N tilde ; B 248 565 572 668 ; +C 127 ; WX 511.11 ; N dieresis ; B 268 565 552 669 ; +C -1 ; WX 357.78 ; N space ; B 357 0 358 0 ; +EndCharMetrics +StartKernData +StartKernPairs 180 +KPX A C -25.56 +KPX A G -25.56 +KPX A O -25.56 +KPX A Q -25.56 +KPX A T -76.67 +KPX A U -25.56 +KPX A V -102.22 +KPX A W -102.22 +KPX A Y -76.67 +KPX A a -51.11 +KPX A b -25.56 +KPX A c -51.11 +KPX A d -51.11 +KPX A e -51.11 +KPX A g -51.11 +KPX A h -25.56 +KPX A i -25.56 +KPX A k -25.56 +KPX A l -25.56 +KPX A m -25.56 +KPX A n -25.56 +KPX A o -51.11 +KPX A q -51.11 +KPX A r -25.56 +KPX A t -25.56 +KPX A u -25.56 +KPX A v -25.56 +KPX A w -25.56 +KPX D A -25.56 +KPX D V -25.56 +KPX D W -25.56 +KPX D X -25.56 +KPX D Y -25.56 +KPX F A -102.22 +KPX F C -25.56 +KPX F G -25.56 +KPX F O -25.56 +KPX F Q -25.56 +KPX F a -76.67 +KPX F e -76.67 +KPX F o -76.67 +KPX F r -76.67 +KPX F u -76.67 +KPX K C -25.56 +KPX K G -25.56 +KPX K O -25.56 +KPX K Q -25.56 +KPX L T -76.67 +KPX L V -102.22 +KPX L W -102.22 +KPX L Y -76.67 +KPX L a -51.11 +KPX L c -51.11 +KPX L d -51.11 +KPX L e -51.11 +KPX L g -51.11 +KPX L o -51.11 +KPX L q -51.11 +KPX O A -25.56 +KPX O V -25.56 +KPX O W -25.56 +KPX O X -25.56 +KPX O Y -25.56 +KPX P A -76.67 +KPX R C -25.56 +KPX R G -25.56 +KPX R O -25.56 +KPX R Q -25.56 +KPX R T -76.67 +KPX R U -25.56 +KPX R V -102.22 +KPX R W -102.22 +KPX R Y -76.67 +KPX R a -51.11 +KPX R b -25.56 +KPX R c -51.11 +KPX R d -51.11 +KPX R e -51.11 +KPX R g -51.11 +KPX R h -25.56 +KPX R i -25.56 +KPX R k -25.56 +KPX R l -25.56 +KPX R m -25.56 +KPX R n -25.56 +KPX R o -51.11 +KPX R q -51.11 +KPX R r -25.56 +KPX R t -25.56 +KPX R u -25.56 +KPX R v -25.56 +KPX R w -25.56 +KPX T A -76.67 +KPX T a -76.67 +KPX T e -76.67 +KPX T o -76.67 +KPX T r -76.67 +KPX T u -76.67 +KPX T y -76.67 +KPX V A -102.22 +KPX V C -25.56 +KPX V G -25.56 +KPX V O -25.56 +KPX V Q -25.56 +KPX V a -76.67 +KPX V e -76.67 +KPX V o -76.67 +KPX V r -76.67 +KPX V u -76.67 +KPX W A -76.67 +KPX X C -25.56 +KPX X G -25.56 +KPX X O -25.56 +KPX X Q -25.56 +KPX Y A -76.67 +KPX Y a -76.67 +KPX Y e -76.67 +KPX Y o -76.67 +KPX Y r -76.67 +KPX Y u -76.67 +KPX b a -51.11 +KPX b c -51.11 +KPX b d -51.11 +KPX b e -51.11 +KPX b g -51.11 +KPX b o -51.11 +KPX b q -51.11 +KPX c a -51.11 +KPX c c -51.11 +KPX c d -51.11 +KPX c e -51.11 +KPX c g -51.11 +KPX c o -51.11 +KPX c q -51.11 +KPX d l 51.11 +KPX e a -51.11 +KPX e c -51.11 +KPX e d -51.11 +KPX e e -51.11 +KPX e g -51.11 +KPX e o -51.11 +KPX e q -51.11 +KPX f bracketright 104.31 +KPX f exclam 104.31 +KPX f parenright 104.31 +KPX f question 104.31 +KPX f quoteright 104.31 +KPX ff bracketright 104.31 +KPX ff exclam 104.31 +KPX ff parenright 104.31 +KPX ff question 104.31 +KPX ff quoteright 104.31 +KPX l l 51.11 +KPX n quoteright -102.22 +KPX o a -51.11 +KPX o c -51.11 +KPX o d -51.11 +KPX o e -51.11 +KPX o g -51.11 +KPX o o -51.11 +KPX o q -51.11 +KPX p a -51.11 +KPX p c -51.11 +KPX p d -51.11 +KPX p e -51.11 +KPX p g -51.11 +KPX p o -51.11 +KPX p q -51.11 +KPX polishlcross L -320.55 +KPX polishlcross l -255.55 +KPX quoteright exclam 102.22 +KPX quoteright question 102.22 +KPX r a -51.11 +KPX r c -51.11 +KPX r d -51.11 +KPX r e -51.11 +KPX r g -51.11 +KPX r o -51.11 +KPX r q -51.11 +KPX w l 51.11 +EndKernPairs +EndKernData +EndFontMetrics 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/cmti10.ttf b/lib/matplotlib/mpl-data/fonts/ttf/cmti10.ttf new file mode 100644 index 000000000000..8311a98ac9e3 Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/cmti10.ttf 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&,01.,)&#m{X@&1;AB=4-)%!lzS{"}.$+3CR^7($t9&w&*.:Uˈʏ˔zqs$(+Pt {izr!%(s~ yjz!s"%7u | wk{,w!#1lged~ z -t(tK 0ݼ+ { vnK撹 u-ݺ( | -xsk{2x*۹% { -xt -n=曼+z&F} z wso!m}[0}~~} | z -xurol{QG~ y y y -x vuspo,s性6yD0 vrq r)z-vSݏ^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&,01.,)&#m{X@&1;AB=4-)%!lzS{"}.$+3CR^aVMt9&w&*.:jЎ،׉Նzqs$(+/ {izr!%(+}㍾~ yjz!s"%'{ƿ | wk{,w!#_̈ɈɆȼ~ z -t(tK !! & { vnK撹 u | -xsk{2x { -xt -n=曼+zD} z wso!m}[0}~~} | z -xurol{QG~ y y y -x vuspo,s性6yD0 vrq r)z-vSݏ^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 -pVpɸ쓻TSX쓼WVZ씽c\\얿pggø呺ГӓӖՑ|okȸcQU^nq[SPVSPdLPU[ituk\UQMIEXhOQT[`g`UZWURPuƸ쓼ZW[쓼UTX쓻QPW쒺NMU쐺JIRiTmø \ 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$"hfsgsecVx#2Dy00usݳяjO־w!Y4Q/K#;w/.usݳڌ-s:O@[6R0L&B"?!:w/.us䰆wXy'-56>,2!9"? ;w/.ghx=O=Uhs116"? ;w/.s>R@[f!#n11!8"?!:w/.Թu=RE^d !i//'?"?#;w/.ԹuAVJbh-/кf+*)A"?#;w.-ؿw!DYKdg)+ſvo^XJʵe))+A"?2l{--AUIa??mqqj٨Ԗ}ҙOD4ɻҔy43&9m̲漢GP@?p|~wnљݳԘ~eUkhϙn$"ɥv41r}tcԗإӕ|cLyoϙzscҐՙюxaJyoϙzraΆЍ̈́q]Fyoϙzr`{́zjVByoϙzscptoaP - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ 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)pd榽W^~-qhb^~^~={-rh`^~`e$l5w^~)o:y^~)oD^~)o"kD^~)o$m摰%lammmmm#k^hmtzzza/sMd^~^~^~^~^~^~^~^~b^~^~^~^~^~^~^~^~eXcVe^~^~^~^~^~^~^~^~b^~^~^~^~^~^~^~^~`Kdn9y`_____f_~fmf___a(n_+p5w^~)o,q5w^~)o5w^~)o5w^~)o,qg`^~_b$lZ^~^~^~D榽H^~-qu(ndY \ 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ݠpeӠk߷ޑRȗԙ~a2ܖ^yעϊoTe։LФҤҥԪޮZѡӗ|`ZݘVۦ~խݿ߽ݺۺܫ۹Ȝ|ﺃأΈmUiْ[Ѷ޷ڲתگڣly^VّT޵ӵݍ՝ޟޙۓ،Ԅπ̓ҼI×T_Ŕؔ؈׵њpкۤӺߔ^LFDB:zҷٽݏ߱۞Ҵ׸ڊg\XSNGxзڲ׃ЖΒ̍ʈǃÅĤ٭~ʾoifb]X٧yȸtnlhdx֑Ϣծ۱ۭܰ٬آԨ޷ۤԡ՝Ѡӥҿϖږږږږږږږڗۗۗۗۗۗۗۗۊ \ 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..dc526effeebe --- /dev/null +++ b/lib/matplotlib/mpl-data/kpsewhich.lua @@ -0,0 +1,4 @@ +-- see dviread._LuatexKpsewhich +kpse.set_program_name("latex") +kpse.init_prog("", 600, "ljfour") +while true do print(kpse.lookup(io.read():gsub("\r", ""), {mktexpk=true})); 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..3b8d222bb3a0 --- /dev/null +++ b/lib/matplotlib/mpl-data/matplotlibrc @@ -0,0 +1,849 @@ +#### 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 'small', 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 + +#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 + +## The language of the text in a format accepted by libraqm, namely `a BCP47 language +## code `_. If None, then no +## particular language will be implied, and default font settings will be used. +#text.language: None + +## 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: default + +#text.hinting_factor: None # This setting does nothing and is deprecated. +#text.kerning_factor: None # Specifies the scaling factor for kerning values. Values + # other than 0, 6, or None have no defined meaning. + # This setting is deprecated. +#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 + +## The TeX engine/format to use. The following values are supported: +## - "latex": The classic TeX engine (the current default). All backends render +## TeX's output by parsing the DVI output into glyphs and boxes and emitting +## those one by one. +## - "latex+dvipng": The same as "latex", with the exception that Agg-based +## backends rely on dvipng to rasterize TeX's output. This value was the +## default up to Matplotlib 3.10. +#text.latex.engine: latex + +#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: normal # The default font to use for math. + # Can be any of the LaTeX font names (normal, it, bf, + # etc.), 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) +#axes3d.snap_rotation: 5.0 # Snap angle (degrees) for 3D rotation when holding Control. +## *************************************************************************** +## * 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 + +#grid.major.color: None # If None defaults to grid.color +#grid.major.linestyle: None # If None defaults to grid.linestyle +#grid.major.linewidth: None # If None defaults to grid.linewidth +#grid.major.alpha: None # If None defaults to grid.alpha + +#grid.minor.color: None # If None defaults to grid.color +#grid.minor.linestyle: None # If None defaults to grid.linestyle +#grid.minor.linewidth: None # If None defaults to grid.linewidth +#grid.minor.alpha: None # If None defaults to grid.alpha + + +## *************************************************************************** +## * 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.linewidth: None # line width of the legend frame, None means inherit from patch.linewidth +#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. + # If set to False, we currently do not take any further + # actions and whether the window appears on the front + # may depend on the GUI framework and window manager. + +## 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 +#errorbar.capthick: None # thickness of end cap on error bars in points +#errorbar.elinewidth: None # line width of error bar lines in points + + +## *************************************************************************** +## * 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..03a97a7b3cd9 --- /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..3dde19c0884b --- /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. + +ytick.alignment: center_baseline + +hatch.color: edge + +text.hinting: default 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..508445362f3a 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 @@ -8,8 +8,6 @@ patch.facecolor: blue patch.edgecolor: eeeeee patch.antialiased: True -text.hinting_factor : 8 - mathtext.fontset : cm axes.facecolor: eeeeee @@ -17,6 +15,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']) + +grid.color: b2b2b2 +grid.linestyle: -- +grid.linewidth: 0.5 + +legend.fancybox: True -legend.fancybox: True \ No newline at end of file +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..43753c693fea --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle @@ -0,0 +1,491 @@ +### 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 'small', 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 +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.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: normal # The default font to use for math. + # Can be any of the LaTeX font names (normal, it, bf, + # etc.), 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/offsetbox.py b/lib/matplotlib/offsetbox.py index b014950a4930..ca19a26f2b17 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"): - """ - 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'. +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. """ - - 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): + 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). - accepts extent of the box + The extent parameters have to be provided to handle the case where the + offset is dynamically determined by a callable (see + `~.OffsetBox.set_offset`). + + 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 + VPacker packs its children vertically, automatically adjusting their + relative positions at draw time. - width and height of the container box, calculated if - `None`. + .. code-block:: none - align : str, optional - Alignment of boxes. - - mode : str, optional - 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(VPacker, self).__init__(pad, sep, width, height, - align, mode, - children) - - 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) - - pack_list = [(h, yd) for w, h, xd, yd in whd_list] - height, yoffsets_ = _get_packed_offsets(pack_list, self.height, - sep, self.mode) + 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) - 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. + HPacker packs its children horizontally, automatically adjusting their + relative positions at draw time. - width : float, optional + .. code-block:: none - height : float, optional - Width and height of the container box, calculated if - `None`. - - align : str - Alignment of boxes. - - 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) + 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), [] - pack_list = [(w, xd) for w, h, xd, yd in whd_list] + (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) - width, xoffsets_ = _get_packed_offsets(pack_list, self.width, - sep, self.mode) + x0 = bboxes[0].x0 + xoffsets -= ([bbox.x0 for bbox in bboxes] - x0) - xoffsets = xoffsets_ + [xd for w, h, xd, yd in whd_list] - - 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,431 +645,384 @@ 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) - - bbox, info, d = self._text._get_layout(renderer) - w, h = bbox.width, bbox.height + 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) - line = info[-1][0] # last line + bbox, info, _ = self._text._get_layout(renderer) + _last_line, (_last_width, _last_ascent, last_descent), _last_xy = info[-1] + 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, last_descent - yd_new) + last_descent = yd_new else: # single line + h_d = max(h_ - d_, h - last_descent) + h = h_d + last_descent - 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 - - h = h_d + d + ha = self._text.get_horizontalalignment() + x0 = {"left": 0, "center": -w / 2, "right": -w}[ha] - return w, h, 0., d + return Bbox.from_bounds(x0, -last_descent, 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 - transformed with the aux_transform first then will be - offseted. 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 - offset transform. - - It is similar to drawing area, except that the extent of the box - is not predetermined but calculated from the window extent of its - children. Furthermore, the extent of the children will be - calculated in the transformed coordinate. + An OffsetBox with an auxiliary transform. + + All child artists are first transformed with *aux_transform*, then + translated with an offset (the same for all children) so the bounding + box of the children matches the drawn box. (In other words, adding an + arbitrary translation to *aux_transform* has no effect as it will be + cancelled out by the later offsetting.) + + `AuxTransformBox` is similar to `.DrawingArea`, except that the extent of + the box is not predetermined but calculated from the window extent of its + children, and the extent of the children will be calculated in the + transformed coordinate. """ 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 the `.Transform` applied to the children.""" + 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 OffsetBox 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 or (float, float), default: 0.5 + Padding between the offsetbox frame and the *bbox_to_anchor*. + If a float, the same padding is used for both x and y. + If a tuple of two floats, it specifies the (x, y) padding. + + .. versionadded:: 3.11 + The *borderpad* parameter now accepts a tuple of (x, y) paddings. + 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.getitem_checked(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 +1030,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 +1046,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 +1055,61 @@ 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 + fontsize_in_pixels = renderer.points_to_pixels(self.prop.get_size_in_points()) + try: + borderpad_x, borderpad_y = self.borderpad + except TypeError: + borderpad_x = self.borderpad + borderpad_y = self.borderpad + pad_x_pixels = borderpad_x * fontsize_in_pixels + pad_y_pixels = borderpad_y * fontsize_in_pixels + 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_x_pixels, + pad_y_pixels + ) + 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, pad_x, pad_y): + """ + Return the (x, y) position of the *bbox* anchored at the *parentbbox* with + the *loc* code with the *borderpad* and padding *pad_x*, *pad_y*. + """ + # 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(-pad_x, -pad_y) + return bbox.anchored(c, container=container).p0 class AnchoredText(AnchoredOffsetbox): @@ -1147,64 +1117,122 @@ 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, + """ + Container artist for images. + + Image data is displayed using `.BboxImage`. This image is meant to be positioned + relative to a parent artist. + + Parameters + ---------- + arr: array-like or `PIL.Image.Image` + 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 + + zoom: float, default: 1 + zoom factor: + + - no zoom: factor =1 + - zoom in: factor > 1 + - zoom out: 0< factor < 1 + + cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` + The Colormap instance or registered colormap name used to map scalar + data to colors. This parameter is ignored if X is RGB(A). + + norm : str or `~matplotlib.colors.Normalize`, default: None + Maps luminance to 0-1. This parameter is ignored if X is RGB(A). + + 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. + + dpi_cor: bool, default: True + Correct for the backend DPI setting + + **kwargs : `.BboxImage` properties + + """ + 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 +1251,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 +1312,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 +1397,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 +1417,7 @@ def xyann(self): @xyann.setter def xyann(self, xyann): self.xybox = xyann + self.stale = True @property def anncoords(self): @@ -1391,17 +1426,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 +1443,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 +1450,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) - - x, y = xy_pixel + self.patch.set_bounds(bbox.bounds) - 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(): - return - - xy_pixel = self._get_position_xy(renderer) - - if not self._check_xy(renderer, xy_pixel): + # docstring inherited + if not self.get_visible() or not self._check_xy(renderer): 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 - - *saveoffset* is called when the object is picked for dragging and it is - meant to save reference position of the artist. + Helper base class for a draggable artist (legend, offsetbox). - *update_offset* is called during the dragging. dx and dy is the pixel - offset from the point where the mouse drag started. + Derived classes must override the following methods:: - Optionally you may override following two methods. + def save_offset(self): + ''' + Called when the object is picked for dragging; should save the + reference position of the artist. + ''' - def artist_picker(self, artist, evt): - return self.ref_artist.contains(evt) + 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 finalize_offset(self): - pass + Optionally, you may override the following method:: - *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: + 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.draw() - - def on_motion_blit(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.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 +1651,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 +1666,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..36f31908eebf --- /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 | tuple[float, 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 | tuple[float, 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 f99ed0f52291..cdd03bcd7e89 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -1,61 +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.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 - - -# 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. @@ -64,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, @@ -81,54 +56,58 @@ def __init__(self, fill=True, capstyle=None, joinstyle=None, + hatchcolor=None, + edgegapcolor=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._gapcolor = None + 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() + self.set_edgegapcolor(edgegapcolor) 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() @@ -137,74 +116,215 @@ 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._gapcolor = other._gapcolor + 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 @@ -213,158 +333,242 @@ 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'] - # save: otherwise changing _fill may lose alpha information self._original_facecolor = color - 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._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) - # using self._fill and self._alpha - self.set_facecolor(self._original_facecolor) - self.set_edgecolor(self._original_edgecolor) + self._original_hatchcolor = color + self._set_hatchcolor(color) + + def get_edgegapcolor(self): + """ + Return the edge gap color. + + .. versionadded:: 3.11 + + See also `~.Patch.set_edgegapcolor`. + """ + return self._gapcolor + + def set_edgegapcolor(self, edgegapcolor): + """ + Set a color to fill the gaps in the dashed edge style. + + .. versionadded:: 3.11 + + .. note:: + + Striped edges 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 + ---------- + edgegapcolor : :mpltype:`color` or None + The color with which to fill the gaps. If None, the gaps are + unfilled. + """ + if edgegapcolor is not None: + self._gapcolor = colors.to_rgba(edgegapcolor, self._alpha) + else: + self._gapcolor = None + self.stale = True + + 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'] + w = mpl._val_or_rc(w, 'patch.linewidth') + w = float(w) self._linewidth = w - - def set_lw(self, lw): - """alias for set_linewidth""" - return self.set_linewidth(lw) + 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. + + Parameters + ---------- + ls : {'-', '--', '-.', ':', '', ...} or (offset, on-off-seq) + Possible values: - ACCEPTS: ['solid' | 'dashed' | 'dashdot' | 'dotted'] + - 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 + ======================================================= ================ + + - A tuple describing the start position and lengths of dashes and spaces: + + (offset, onoffseq) + + where + + - *offset* is a float specifying the offset (in points); i.e. how much + is the dash pattern shifted. + - *onoffseq* is a sequence of on and off ink in points. There can be + arbitrary many pairs of on and off values. + + Example: The tuple ``(0, (10, 5, 1, 5))`` means that the pattern starts + at the beginning of the line. It draws a 10 point long dash, + then a 5 point long space, then a 1 point long dash, followed by a 5 point + long space, and then the pattern repeats. + + For examples see :doc:`/gallery/lines_bars_and_markers/linestyles`. """ 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 @@ -372,41 +576,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`. - ACCEPTS: ['butt' | 'round' | 'projecting'] + The default capstyle is 'round' for `.FancyArrowPatch` and 'butt' for + all other patches. + + 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`. + + The default joinstyle is 'round' for `.FancyArrowPatch` and 'miter' for + all other patches. - ACCEPTS: ['miter' | 'round' | 'bevel'] + 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:: @@ -425,33 +637,56 @@ 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 _has_dashed_edge(self): + """ + Return whether the patch edge has a dashed linestyle. + + A custom linestyle is assumed to be dashed, we do not inspect the + ``onoffseq`` directly. + + See also `~.Patch.set_linestyle`. + """ + return self._linestyle not in ('solid', '-') + + 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() - 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_capstyle(self._capstyle) gc.set_joinstyle(self._joinstyle) @@ -460,107 +695,123 @@ 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) + # We first draw a path within the gaps if needed, but only for visible + # dashed edges; zero-width edges would otherwise yield all-zero dashes. + if lw > 0 and self._has_dashed_edge() and self._gapcolor is not None: + gc.set_foreground(self._gapcolor, isRGBA=True) + offset_gaps, gaps = mlines._get_inverse_dash_pattern( + *self._dash_pattern) + gc.set_dashes(offset_gaps, gaps) + for draw_path_args in draw_path_args_list: + renderer.draw_path(gc, *draw_path_args) + + # Draw the main edge + gc.set_foreground(self._edgecolor, isRGBA=True) + if lw > 0: + gc.set_dashes(*self._dash_pattern) + else: + gc.set_dashes(0, None) + 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*. - kwargs are - %(Patch)s + 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 + 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() @@ -569,398 +820,537 @@ 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 + + See Also + -------- + FancyBboxPatch : A rectangle with a fancy box style, e.g. rounded corners. + """ + 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 @@ -983,39 +1373,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: @@ -1025,43 +1417,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) + _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]]) - @docstring.dedent_interpd - def __init__(self, x, y, dx, dy, width=1.0, **kwargs): + @_docstring.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*. - - Valid kwargs are: - %(Patch)s - """ - Patch.__init__(self, **kwargs) - L = np.hypot(dx, dy) - - if L != 0: - cx = float(dx) / L - sx = float(dy) / L - else: - # Account for division by zero - cx, sx = 0, 1 + 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 @@ -1069,306 +1465,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, + @_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. - *length_includes_head*: [True | False] (default: False) + width : float, default: 0.001 + Width of full arrow tail. + + 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.hypot(dx, dy) + distance = np.hypot(self._dx, self._dy) - if length_includes_head: + if self._length_includes_head: length = distance else: length = distance + head_length - if not length: - verts = [] # display nothing if empty + if np.size(length) == 0: + 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 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] + if self._head_starts_at_zero: + left_half_arrow += [head_length / 2, 0] # figure out the shape, and complete accordingly - if shape == 'left': + 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) + raise ValueError(f"Got unknown shape: {self._shape!r}") if distance != 0: - cx = float(dx) / distance - sx = float(dy) / distance + cx = self._dx / distance + sx = self._dy / distance else: - #Account for division by zero + # Account for division by zero cx, sx = 0, 1 - M = np.array([[cx, sx], [-sx, cx]]) - verts = np.dot(coords, M) + (x + dx, y + dy) + 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`. - @docstring.dedent_interpd - def __init__(self, figure, xytip, xybase, - width=4, frac=0.1, headwidth=12, **kwargs): + Valid keyword arguments are: + + %(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. - def getpoints(self, x1, y1, x2, y2, k): + Parameters + ---------- + width : float + """ + self._width = width + self.stale = True + + 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 - Valid kwargs are: - %(Patch)s + angle = property(get_angle, set_angle) + def get_corners(self): """ - RegularPolygon.__init__(self, xy, - resolution, - radius, - orientation=0, - **kwargs) + 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)]) -class Ellipse(Patch): + def get_vertices(self): + """ + Return the 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([(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) + + return "Annulus(xy=(%s, %s), r=%s, width=%s, angle=%s)" % \ + (*self.center, r, self.width, self.angle) - @docstring.dedent_interpd - def __init__(self, xy, width, height, angle=0.0, **kwargs): + 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): + """ + Set the tilt angle of the annulus. + + Parameters + ---------- + angle : float """ - Return the vertices of the rectangle + self._angle = angle + self._path = None + self.stale = True + + def get_angle(self): + """Return the angle of the annulus.""" + return self._angle + + angle = property(get_angle, set_angle) + + def set_semimajor(self, a): """ - return self._path + Set the semi-major axis *a* of the annulus. - def get_patch_transform(self): - self._recompute_transform() - return self._patch_transform + Parameters + ---------- + a : float + """ + self.a = float(a) + self._path = None + self.stale = True - 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, {} + 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): @@ -1376,35 +2070,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*. - Valid kwargs are: - %(Patch)s + Unlike `CirclePolygon` which is a polygonal approximation, this uses + Bezier splines and is much closer to a scale-free circle. + 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) @@ -1412,72 +2109,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 @@ -1491,71 +2197,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 @@ -1565,56 +2266,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: @@ -1624,12 +2312,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 @@ -1641,185 +2368,125 @@ 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): +class _Style: """ - Given the list of list of strings, return a string of REST table format. + 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. """ - 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) + 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 = 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 = {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}) - col_len = [max([len(cell) for cell in column]) for column in columns] + @classmethod + def get_styles(cls): + """Return a dictionary of available styles.""" + return cls._style_list - 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) - - -def _simpleprint_styles(_styles): - """ - A helper function for the _Style class. Given the dictionary of - (stylename : styleclass), return a string rep of the list of keys. - Used to update the documentation. - """ - styles = "[ \'" - styles += "\' | \'".join(str(i) for i in sorted(_styles.keys())) - styles += "\' ]" - return styles - - -class _Style(object): - """ - 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. - - _list = stylename.replace(" ", "").split(",") - _name = _list[0].lower() - try: - _cls = self._style_list[_name] - except KeyError: - raise ValueError("Unknown style : %s" % stylename) - - 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) - - @classmethod - def get_styles(klass): - """ - A class method which returns a dictionary of available styles. - """ - return klass._style_list - - @classmethod - def pprint_styles(klass): - """ - A class method which returns a string of the available styles. - """ - return _pprint_styles(klass._style_list) + @classmethod + 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', + 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:: @@ -1833,286 +2500,245 @@ class BoxStyle(_Style): BoxStyle("Round, pad=0.2") - Following boxstyle classes are defined. + The following boxstyle classes are defined. - %(AvailableBoxstyles)s - - 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. - """ - - # 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.): - """ - 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. - """ - # 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) - - 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__ - ) - - class Square(_Base): - """ - A simple square box. - """ + @_register_style(_style_list) + class Square: + """A square 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, + x0, y0 = x0 - pad, y0 - pad x1, y1 = x0 + width, y0 + height + return Path._create_closed( + [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]) - vertices = [(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)] - codes = [Path.MOVETO] + [Path.LINETO] * 3 + [Path.CLOSEPOLY] - return Path(vertices, codes) - - _style_list["square"] = Square + @_register_style(_style_list) + class Circle: + """A circular box.""" - 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.)) - - _style_list["circle"] = Circle - - class LArrow(_Base): - """ - (left) Arrow Box - """ - def __init__(self, pad=0.3): - self.pad = pad - super(BoxStyle.LArrow, self).__init__() - - def transmute(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 - # 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) - - return path - _style_list["larrow"] = LArrow + x0, y0 = x0 - pad, y0 - pad + return Path.circle((x0 + width / 2, y0 + height / 2), + max(width, height) / 2) - class RArrow(LArrow): + @_register_style(_style_list) + class Ellipse: """ - (right) Arrow Box - """ - - def __init__(self, pad=0.3): - 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) - - p.vertices[:, 0] = 2 * x0 + width - p.vertices[:, 0] - - return p - - _style_list["rarrow"] = RArrow + An elliptical box. - class DArrow(_Base): + .. versionadded:: 3.7 """ - (Double) Arrow Box - """ - # This source is copied from LArrow, - # modified 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): - - # padding + def __call__(self, x0, y0, width, height, mutation_size): 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 - + 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), # 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] + 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()) - path = Path(cp, com) + @_register_style(_style_list) + class RArrow: + """A box in the shape of a right-pointing arrow.""" - return path + def __init__(self, pad=0.3, head_width=1.5, head_angle=90): + """ + Parameters + ---------- + pad : float, default: 0.3 + The amount of padding around the original box. + head_width : float, default: 1.5 + The head width, relative to the arrow shaft width; must be + nonnegative. + head_angle : float, default: 90 + The angle at the tip of the arrow, in degrees; must be nonzero + (modulo 360). Negative angles result in arrow heads pointing + backwards. + """ + self.pad = pad + if head_width < 0: + raise ValueError("'head_width' must be nonnegative") + self.head_width = head_width + if head_angle % 360 == 0: + raise ValueError("'head_angle' must be nonzero") + self.head_angle = head_angle + + def __call__(self, x0, y0, width, height, mutation_size): + # padding & padded dimensions + pad = mutation_size * self.pad + dx, dy = width + 2 * pad, height + 2 * pad + x0, y0 = x0 - pad, y0 - pad, + x1, y1 = x0 + dx, y0 + dy + + head_dy = self.head_width * dy + mid_y = (y0 + y1) / 2 + shaft_y0 = mid_y - head_dy / 2 + shaft_y1 = mid_y + head_dy / 2 + + cot = 1 / math.tan(math.radians(self.head_angle / 2)) + + if cot > 0: + # tip_x is chosen s.t. the angled line moving back from the tip hits + # i) if head_width > 1: the box corner, or ii) if head_width < + # 1 the box edge at the point giving the correct shaft width. + tip_x = x1 + cot * min(dy, head_dy) / 2 + shaft_x = tip_x - cot * head_dy / 2 + return Path._create_closed([ + (x0, y0), (shaft_x, y0), (shaft_x, shaft_y0), + (tip_x, mid_y), + (shaft_x, shaft_y1), (shaft_x, y1), (x0, y1), + ]) + else: # Reverse arrowhead. + # Make the long (outer) side of the arrowhead flush with the + # original box, and move back accordingly (but clipped to no + # more than the box length). If this clipping is necessary, + # the y positions at the short (inner) side of the arrowhead + # will be thicker than the original box, hence the need to + # recompute mid_y0 & mid_y1. + # If head_width < 1 no arrowhead is drawn. + dx = min(-cot * max(head_dy - dy, 0) / 2, dx) # cot < 0! + mid_y0 = min(shaft_y0, y0) - dx / cot + mid_y1 = max(shaft_y1, y1) + dx / cot + return Path._create_closed([ + (x0, y0), (x1 - dx, mid_y0), (x1, shaft_y0), + (x1, shaft_y1), (x1 - dx, mid_y1), (x0, y1), + ]) + + @_register_style(_style_list) + class LArrow(RArrow): + """A box in the shape of a left-pointing arrow.""" + + def __call__(self, x0, y0, width, height, mutation_size): + p = super().__call__(x0, y0, width, height, mutation_size) + p.vertices[:, 0] = 2 * x0 + width - p.vertices[:, 0] + return p - _style_list['darrow'] = DArrow + @_register_style(_style_list) + class DArrow(RArrow): + """A box in the shape of a two-way arrow.""" + # Modified from RArrow to have arrows on both sides; see comments above. - class Round(_Base): - """ - A box with round corners. - """ + def __call__(self, x0, y0, width, height, mutation_size): + # padding & padded dimensions + pad = mutation_size * self.pad + dx, dy = width + 2 * pad, height + 2 * pad + x0, y0 = x0 - pad, y0 - pad, + x1, y1 = x0 + dx, y0 + dy + + head_dy = self.head_width * dy + mid_y = (y0 + y1) / 2 + shaft_y0 = mid_y - head_dy / 2 + shaft_y1 = mid_y + head_dy / 2 + + cot = 1 / math.tan(math.radians(self.head_angle / 2)) + + if cot > 0: + tip_x0 = x0 - cot * min(dy, head_dy) / 2 + shaft_x0 = tip_x0 + cot * head_dy / 2 + tip_x1 = x1 + cot * min(dy, head_dy) / 2 + shaft_x1 = tip_x1 - cot * head_dy / 2 + return Path._create_closed([ + (shaft_x0, y1), (shaft_x0, shaft_y1), + (tip_x0, mid_y), + (shaft_x0, shaft_y0), (shaft_x0, y0), + (shaft_x1, y0), (shaft_x1, shaft_y0), + (tip_x1, mid_y), + (shaft_x1, shaft_y1), (shaft_x1, y1), + ]) + else: + # Don't move back by more than half the box length. + dx = min(-cot * max(head_dy - dy, 0) / 2, dx / 2) # cot < 0! + mid_y0 = min(shaft_y0, y0) - dx / cot + mid_y1 = max(shaft_y1, y1) + dx / cot + return Path._create_closed([ + (x0, shaft_y0), (x0 + dx, mid_y0), + (x1 - dx, mid_y0), (x1, shaft_y0), + (x1, shaft_y1), (x1 - dx, mid_y1), + (x0 + dx, mid_y1), (x0, shaft_y1), + ]) + + @_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), @@ -2136,43 +2762,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 @@ -2191,28 +2811,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): @@ -2225,489 +2840,169 @@ 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]) 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), - ListBoxstyles=_simpleprint_styles(BoxStyle._style_list)) - - -class FancyBboxPatch(Patch): +@_docstring.interpd +class ConnectionStyle(_Style): """ - 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. + `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 `FancyArrowPatch`. - """ + A connectionstyle object can be either created as:: - 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 + ConnectionStyle.Arc3(rad=0.2) - *width*, *height* + or:: - *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. + ConnectionStyle("Arc3", rad=0.2) - %(AvailableBoxstyles)s + or:: - *mutation_scale* : a value with which attributes of boxstyle - (e.g., pad) will be scaled. default=1. + ConnectionStyle("Arc3, rad=0.2") - *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. + The following classes are defined - Valid kwargs are: - %(Patch)s - """ + %(ConnectionStyle:table)s - Patch.__init__(self, **kwargs) + An instance of any connection style class is a callable object, + whose call signature is:: - self._x = xy[0] - self._y = xy[1] - self._width = width - self._height = height + __call__(self, posA, posB, + patchA=None, patchB=None, + shrinkA=2., shrinkB=2.) - 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) + 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. + """ - self._mutation_scale = mutation_scale - self._mutation_aspect = mutation_aspect + _style_list = {} - @docstring.dedent_interpd - def set_boxstyle(self, boxstyle=None, **kw): + class _Base: """ - Set the box style. + A base class for connectionstyle classes. The subclass needs + to implement a *connect* method whose call signature is:: - *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) + connect(posA, posB) - Old attrs simply are forgotten. + where posA and posB are tuples of x, y coordinates to be + connected. The method needs to return a path connecting two + points. This base class defines a __call__ method, and a few + helper methods. + """ + def _in_patch(self, patch): + """ + 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] - Without argument (or with *boxstyle* = None), it returns - available box styles. + 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 following boxstyles are available: - %(AvailableBoxstyles)s + The original path is assumed to start in the *in_start* region and + to stop in the *in_stop* region. + """ + if in_start: + try: + _, path = split_path_inout(path, in_start) + except ValueError: + pass + if in_stop: + try: + path, _ = split_path_inout(path, in_stop) + except ValueError: + pass + return path - ACCEPTS: %(ListBoxstyles)s + def __call__(self, posA, posB, + shrinkA=2., shrinkB=2., patchA=None, patchB=None): + """ + 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 + @_register_style(_style_list) + class Arc3(_Base): """ - 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) - - -class ConnectionStyle(_Style): - """ - :class:`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`. - - A connectionstyle object can be either created as:: - - ConnectionStyle.Arc3(rad=0.2) - - or:: - - ConnectionStyle("Arc3", rad=0.2) - - or:: - - ConnectionStyle("Arc3, rad=0.2") - - The following classes are defined - - %(AvailableConnectorstyles)s - - - An instance of any connection style class is an 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 - 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): - """ - A base class for connectionstyle classes. The dervided needs - to implement a *connect* methods 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 - helper methods. - """ - - class SimpleEvent: - def __init__(self, xy): - self.x, self.y = xy - - def _clip(self, path, patchA, patchB): - """ - 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. - """ - - if patchA: - def insideA(xy_display): - xy_event = ConnectionStyle._Base.SimpleEvent(xy_display) - return patchA.contains(xy_event)[0] - - 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 - except ValueError: - pass - - if shrinkB: - x, y = path.vertices[-1] - insideB = inside_circle(x, y, shrinkB) - - try: - left, right = split_path_inout(path, insideB) - path = left - 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. - """ - - path = self.connect(posA, posB) - - 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__ - ) - - class Arc3(_Base): - """ - Creates a simple quadratic bezier curve between two - points. The curve is created so that the middle contol points - (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. + 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. """ def __init__(self, rad=0.): """ - *rad* - curvature of the curve. + Parameters + ---------- + rad : float + Curvature of the curve. """ self.rad = rad @@ -2730,23 +3025,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 @@ -2756,10 +3052,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) @@ -2769,27 +3065,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 @@ -2801,10 +3098,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) @@ -2817,10 +3114,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), @@ -2832,33 +3129,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 @@ -2877,8 +3175,8 @@ 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) + 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)) @@ -2886,8 +3184,8 @@ def connect(self, posA, posB): 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: @@ -2927,27 +3225,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 @@ -2958,8 +3260,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 @@ -2968,20 +3268,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 @@ -2989,17 +3280,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 @@ -3015,17 +3297,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 @@ -3034,13 +3310,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) @@ -3054,28 +3331,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 @@ -3085,121 +3370,148 @@ 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.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 @@ -3235,711 +3547,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 - *lengthA* - length of the bracket + @_docstring.interpd + def set_boxstyle(self, boxstyle=None, **kwargs): + """ + Set the box style, possibly with further attributes. - *angleA* - angle between the bracket and the line + Attributes from the previous box style are not reused. - *widthB* - width of the bracket + Without argument (or with ``boxstyle=None``), the available box styles + are returned as a human-readable string. - *lengthB* - length 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. - *angleB* - angle between the bracket and the line - """ + The following box styles are available: - super(ArrowStyle.BarAB, self).__init__( - True, True, widthA=widthA, lengthA=0, angleA=angleA, - widthB=widthB, lengthB=0, angleB=angleB) + %(BoxStyle:table_and_accepts)s - _style_list["|-|"] = BarAB + **kwargs + Additional attributes for the box style. See the table above for + supported parameters. - class Simple(_Base): - """ - A simple arrow. Only works with a quadratic bezier curve. - """ + Examples + -------- + :: - def __init__(self, head_length=.5, head_width=.5, tail_width=.2): - """ - *head_length* - length of the arrow head + 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 - *head_with* - width of the arrow head + def get_boxstyle(self): + """Return the boxstyle object.""" + return self._bbox_transmuter - *tail_width* - width of the arrow tail + def set_mutation_scale(self, scale): + """ + Set the mutation scale. - """ + Parameters + ---------- + scale : float + """ + self._mutation_scale = scale + self.stale = True - self.head_length, self.head_width, self.tail_width = \ - head_length, head_width, tail_width - super(ArrowStyle.Simple, self).__init__() + def get_mutation_scale(self): + """Return the mutation scale.""" + return self._mutation_scale - def transmute(self, path, mutation_size, linewidth): + def set_mutation_aspect(self, aspect): + """ + Set the aspect ratio of the bbox mutation. - x0, y0, x1, y1, x2, y2 = self.ensure_quadratic_bezier(path) + Parameters + ---------- + aspect : float + """ + self._mutation_aspect = aspect + self.stale = True - # 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_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. - from .bezier import NonIntersectingPathException + 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. - 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 + # Following methods are borrowed from the Rectangle class. - # head - head_width = self.head_width * mutation_size - head_left, head_right = make_wedged_bezier2(arrow_in, - head_width / 2., wm=.5) + def get_x(self): + """Return the left coord of the rectangle.""" + return self._x - # 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_y(self): + """Return the bottom coord of the rectangle.""" + return self._y - 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_width(self): + """Return the width of the rectangle.""" + return self._width - path = Path([p for c, p in patch_path], [c for c, p in patch_path]) + def get_height(self): + """Return the height of the rectangle.""" + return self._height - return path, True + def set_x(self, x): + """ + Set the left coord of the rectangle. - _style_list["simple"] = Simple + Parameters + ---------- + x : float + """ + self._x = x + self.stale = True - class Fancy(_Base): + def set_y(self, y): """ - A fancy arrow. Only works with a quadratic bezier curve. + Set the bottom coord of the rectangle. + + Parameters + ---------- + y : float """ + self._y = y + self.stale = True - def __init__(self, head_length=.4, head_width=.4, tail_width=.4): - """ - *head_length* - length of the arrow head + def set_width(self, w): + """ + Set the rectangle width. - *head_with* - width of the arrow head + Parameters + ---------- + w : float + """ + self._width = w + self.stale = True - *tail_width* - width of the arrow tail + def set_height(self, h): + """ + Set the rectangle height. - """ + Parameters + ---------- + h : float + """ + self._height = h + self.stale = True - self.head_length, self.head_width, self.tail_width = \ - head_length, head_width, tail_width - super(ArrowStyle.Fancy, self).__init__() + def set_bounds(self, *args): + """ + Set the bounds of the rectangle. - def transmute(self, path, mutation_size, linewidth): + Call signatures:: - x0, y0, x1, y1, x2, y2 = self.ensure_quadratic_bezier(path) + set_bounds(left, bottom, width, height) + set_bounds((left, bottom, width, height)) - # divide the path into a head and a tail - head_length = self.head_length * mutation_size - arrow_path = [(x0, y0), (x1, y1), (x2, y2)] + 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 - from .bezier import NonIntersectingPathException + def get_bbox(self): + """Return the `.Bbox`.""" + return transforms.Bbox.from_bounds(self._x, self._y, + self._width, self._height) - # 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 - # 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 +class FancyArrowPatch(Patch): + """ + A fancy arrow patch. - # head - head_width = self.head_width * mutation_size - head_l, head_r = make_wedged_bezier2(path_head, - head_width / 2., - wm=.6) + 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. - # 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) + 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 - # 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] + 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})" - 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]) + @_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** - return path, True + There are two ways to define the arrow position and path: - _style_list["fancy"] = Fancy + - **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*. - 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. + 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. - """ + - **path**: Alternatively if *path* is provided, an arrow is drawn along + this Path. In this case, *connectionstyle*, *patchA*, *patchB*, + *shrinkA*, and *shrinkB* are ignored. - def __init__(self, tail_width=.3, shrink_factor=0.5): - """ - *tail_width* - width of the tail + **Styling** - *shrink_factor* - fraction of the arrow width at the middle point - """ + 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. - self.tail_width = tail_width - self.shrink_factor = shrink_factor - super(ArrowStyle.Wedge, self).__init__() + 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*. - def transmute(self, path, mutation_size, linewidth): + *posA*, *posB* are exclusive of *path*. - x0, y0, x1, y1, x2, y2 = self.ensure_quadratic_bezier(path) + path : `~matplotlib.path.Path`, optional + If provided, an arrow is drawn along this path and *patchA*, + *patchB*, *shrinkA*, and *shrinkB* are ignored. - 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) + *path* is exclusive of *posA*, *posB*. - 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 : str or `.ArrowStyle`, default: 'simple' + The styling of arrow head, tail and shaft. This can be - return path, True + - `.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". - _style_list["wedge"] = Wedge + The style parameters are scaled by *mutation_scale*. - if __doc__: - __doc__ = cbook.dedent(__doc__) % \ - {"AvailableArrowstyles": _pprint_styles(_style_list)} + The following arrow styles are available. See also + :doc:`/gallery/text_labels_and_annotations/fancyarrow_demo`. + %(ArrowStyle:table)s -docstring.interpd.update( - AvailableArrowstyles=_pprint_styles(ArrowStyle._style_list), - AvailableConnectorstyles=_pprint_styles(ConnectionStyle._style_list), -) + Only the styles ``<|-``, ``-|>``, ``<|-|>`` ``simple``, ``fancy`` + and ``wedge`` contain closed paths and can be filled. + connectionstyle : str or `.ConnectionStyle` or None, optional, \ +default: 'arc3' + `.ConnectionStyle` with which *posA* and *posB* are connected. + This can be -class FancyArrowPatch(Patch): - """ - A fancy arrow patch. It draws an arrow using the :class:ArrowStyle. - """ + - `.ConnectionStyle` or one of its subclasses + - The shorthand string name as given in the table below, e.g. "arc3". - def __str__(self): + %(ConnectionStyle:table)s - 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. + Ignored if *path* is provided. + + 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] @@ -3950,17 +4424,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) @@ -3968,120 +4439,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 @@ -4089,56 +4592,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 @@ -4146,77 +4642,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., @@ -4224,15 +4679,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 =============== ====================================================== @@ -4245,33 +4697,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: @@ -4285,191 +4759,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: @@ -4480,16 +4901,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..862eccf4da64 --- /dev/null +++ b/lib/matplotlib/patches.pyi @@ -0,0 +1,771 @@ +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 = ..., + edgegapcolor: ColorType | 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_edgegapcolor(self) -> ColorType | None: ... + 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_edgegapcolor(self, edgegapcolor: 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 RArrow(BoxStyle): + pad: float + head_width: float + head_angle: float + def __init__( + self, pad: float = ..., head_width: float = ..., head_angle: float = ... + ) -> None: ... + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + + class LArrow(RArrow): + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + + class DArrow(RArrow): + pad: float + head_width: float + head_angle: float + def __init__( + self, pad: float = ..., head_width: float = ..., head_angle: 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 90acebb999ae..f65ade669167 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,59 +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 - 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) - if ma.isMaskedArray(verts): - verts = verts.astype(np.float_).filled(np.nan) - else: - verts = np.asarray(verts, np.float_) - 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 @@ -230,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 @@ -258,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): """ @@ -283,82 +268,97 @@ 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): """ - 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. + cls = type(self) + memo[id(self)] = p = cls.__new__(cls) + + for k, v in self.__dict__.items(): + setattr(p, k, copy.deepcopy(v, memo)) + + p._readonly = False + return p - deepcopy = __deepcopy__ + def deepcopy(self, memo=None): + """ + Return a deep copy of the `Path`. The `Path` will not be readonly, + even if the source `Path` is. + + Parameters + ---------- + memo : dict, optional + A dictionary to use for memoizing, passed to `copy.deepcopy`. + + Returns + ------- + Path + A deep copy of the `Path`, but not readonly. + """ + return copy.deepcopy(self, memo) @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.""" - # Handle an empty list in args (i.e. no args). + 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)) - - 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) + 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) @@ -367,45 +367,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. + + 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. + 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 @@ -415,179 +412,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 - *radius* allows the path to be made slightly larger or - smaller. + 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.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. + + 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. + + Returns + ------- + length-N bool array - If *transform* is not *None*, the path will be transformed - before performing the test. + 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.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. - Unlike computing the extents on the *vertices* alone, this - algorithm will take into account the curves and deal with - control points appropriately. + Parameters + ---------- + transform : `~matplotlib.transforms.Transform`, optional + Transform to apply to path before computing extents, if any. + **kwargs + Forwarded to `.iter_bezier`. + + 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`. + + If *filled* is True, then this also returns True if the path completely + encloses the `.Bbox` (i.e., the path is treated as filled). - *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. + 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 [] @@ -596,30 +755,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() @@ -627,8 +789,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: @@ -636,17 +798,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 @@ -656,9 +813,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)) @@ -672,22 +828,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) @@ -699,7 +850,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, @@ -709,31 +859,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], @@ -770,7 +917,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 @@ -782,18 +929,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], @@ -816,9 +959,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 @@ -828,8 +971,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 @@ -837,18 +984,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: @@ -876,8 +1022,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] @@ -885,8 +1031,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 @@ -904,36 +1050,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): """ @@ -945,7 +1087,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) @@ -953,75 +1094,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..8a5a5c03792e --- /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]) -> Path: ... + def deepcopy(self, memo: dict[int, Any] | None = None) -> Path: ... + + @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 19e1c4ae90e4..ae808eb62fbe 100644 --- a/lib/matplotlib/patheffects.py +++ b/lib/matplotlib/patheffects.py @@ -1,51 +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 -import matplotlib.transforms as mtransforms -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) + 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() @@ -53,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 @@ -65,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): @@ -84,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 @@ -101,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]) @@ -133,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]) @@ -144,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): @@ -169,76 +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, 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`. """ - 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) + self._shadow_rgbFace = mcolors.to_rgba(shadow_rgbFace) if alpha is None: alpha = 0.3 @@ -249,141 +254,258 @@ 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: shadow_rgbFace = self._shadow_rgbFace - gc0.set_foreground("none") + gc0.set_foreground(mcolors.to_rgba("none"), isRGBA=True) gc0.set_alpha(self._alpha) 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_rgb() 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_foreground(mcolors.to_rgba(shadow_rgbFace), isRGBA=True) 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..294e5542d706 100644 --- a/lib/matplotlib/projections/__init__.py +++ b/lib/matplotlib/projections/__init__.py @@ -1,50 +1,107 @@ -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 _api, 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*. - """ - return self._all_projection_types[name] + def get_projection_class(self, name, _error_cls=KeyError): + """Get a projection class from its *name*.""" + return _api.getitem_checked(self._all_projection_types, _error_cls=_error_cls, + projection=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 +112,13 @@ 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) + return projection_registry.get_projection_class(projection, _error_cls=ValueError) -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 5e815a0654a6..9d999dde2f6f 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -1,417 +1,1102 @@ -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 + + @_api.delete_parameter('3.11', 'apply_theta_transforms') + def __init__(self, axis=None, use_rmin=True, *, + apply_theta_transforms=False, 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) + @_api.delete_parameter('3.11', 'apply_theta_transforms') + def __init__(self, axis=None, use_rmin=True, + *, apply_theta_transforms=False): + """ + 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) - with np.errstate(invalid='ignore'): - # At x=y=r=0 this will raise an - # invalid value warning when doing 0/0 - # Divide by zero warnings are only raised when - # the numerator is different from 0. That - # should not happen here. - 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 - - return np.concatenate((theta, r), 1) - transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ + __str__ = mtransforms._make_str_method( + "_axis", + use_rmin="_use_rmin") + + 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) + 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 RadialLocator(Locator): +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))) + + 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)) + + +class ThetaTick(maxis.XTick): + """ + A theta-axis tick. - def autoscale(self): - return self.base.autoscale() + 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 pan(self, numsteps): - return self.base.pan(numsteps) + 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 zoom(self, direction): - return self.base.zoom(direction) + 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 - def refresh(self): - return self.base.refresh() + 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). + """ + + @_api.delete_parameter("3.11", "axes") + def __init__(self, base, axes=None): + self.base = base + self._axes = axes + + def set_axis(self, axis): + self.base.set_axis(axis) + + def __call__(self): + # Ensure previous behaviour with full circle non-annular views. + ax = self.base.axis.axes + if _is_full_circle_rad(*ax.viewLim.intervalx): + rorigin = ax.get_rorigin() * ax.get_rsign() + if ax.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.base.axis._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 set_major_locator(self, locator): + if not isinstance(locator, RadialLocator): + locator = RadialLocator(locator) + super().set_major_locator(locator) + + def clear(self): + # docstring inherited + super().clear() + self.set_ticks_position('none') + + +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) + inner_spine = self.spines.get('inner', None) + if inner_spine is not None: + # Subclasses may not have inner spine. + inner_spine.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 + rscale_tr = self.yaxis.get_transform() + rmin, rmax = ((rscale_tr.transform(self._realViewLim.intervaly) - + rscale_tr.transform(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. - May be one of "N", "NW", "W", "SW", "S", "SE", "E", or "NE". + This simply calls `set_theta_offset` with the correct value in radians. + + 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, @@ -421,8 +1106,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): """ @@ -434,14 +1119,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): """ @@ -453,14 +1140,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 get_rsign(self): + return np.sign(self._originViewLim.y1 - self._originViewLim.y0) - def set_rlim(self, *args, **kwargs): + 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): """ @@ -469,155 +1235,218 @@ 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() - - def set_yscale(self, *args, **kwargs): - Axes.set_yscale(self, *args, **kwargs) - self.yaxis.set_major_locator( - self.RadialLocator(self.yaxis.get_major_locator())) + self._r_label_position.clear().translate(np.deg2rad(value), 0.0) 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) - @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. - *labels*, if not None, is a ``len(angles)`` list of strings of - the labels to use at each angle. + fmt : str or None + Format string used in `matplotlib.ticker.FormatStrFormatter`. + For example '%f'. Note that the angle that is used is in + radians. + + 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'. + + Returns + ------- + lines : list of `.lines.Line2D` + The radial gridlines. - 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. + labels : list of `.text.Text` + The tick labels. - kwargs are optional text properties for the labels: + Other Parameters + ---------------- + **kwargs + *kwargs* are optional `.Text` properties for the labels. - %(Text)s + .. warning:: - ACCEPTS: sequence of floats + 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. """ @@ -628,21 +1457,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 @@ -651,17 +1479,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) @@ -673,134 +1495,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..de1cbc293900 --- /dev/null +++ b/lib/matplotlib/projections/polar.pyi @@ -0,0 +1,197 @@ +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 = ..., + *, + apply_theta_transforms: 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 = ..., + *, + apply_theta_transforms: 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 bd1b4936cdc4..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, \ - 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 a13d87ee2ba0..57f5ac08e398 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -1,2150 +1,2676 @@ -# Note: The first part of this file can be modified in place, but the latter -# part is autogenerated by the boilerplate.py script. +# Note: The first part of this file is hand-written and must be edited +# in-place. The second part, starting with +# ### REMAINING CONTENT GENERATED BY boilerplate.py ### +# is generated by the script boilerplate.py. It must not be edited here +# because all changes will be overwritten by the next run of the script. +# For more information see the description in boilerplate.py. + """ -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 IO, 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 +from matplotlib._api import UNSET as _UNSET +# 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 ( + CloseEvent, + DrawEvent, + KeyEvent, + MouseEvent, + PickEvent, + ResizeEvent, + ) + 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, + PieContainer, + 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 + from matplotlib.quiver import Barbs, Quiver, QuiverKey + from matplotlib.scale import ScaleBase + from matplotlib.typing import ( + CloseEventType, + ColorType, + CoordsType, + DrawEventType, + HashableList, + KeyEventType, + LineStyleType, + MarkerType, + MouseEventType, + PickEventType, + RcGroupKeyType, + RcKeyType, + ResizeEventType, + LogLevel + ) + from matplotlib.widgets import SubplotTool + from matplotlib._api import _Unset + + _P = ParamSpec('_P') + _R = TypeVar('_R') + _T = TypeVar('_T') + + # We may not need the following imports here: from matplotlib.colors import Normalize -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 -@docstring.copy_dedent(Artist.findobj) -def findobj(o=None, match=None, include_self=True): - if o is None: - o = gcf() - return o.findobj(match, include_self=include_self) +def _draw_all_if_interactive() -> None: + if matplotlib.is_interactive(): + draw_all() -def switch_backend(newbackend): - """ - 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. - Calling this command will close all open windows. +def install_repl_displayhook() -> None: """ - 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() + 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. -def show(*args, **kw): + This works both with IPython and with vanilla python shells. """ - Display a figure. - When running in ipython with its pylab mode, display all - figures and return to the ipython prompt. + global _REPL_DISPLAYHOOK - 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 _REPL_DISPLAYHOOK is _ReplDisplayHook.IPYTHON: + return - 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) + # 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 -def isinteractive(): - """ - Return status of interactive mode. - """ - return matplotlib.is_interactive() + 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 ioff(): - 'Turn interactive mode off.' - matplotlib.interactive(False) +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 -def ion(): - 'Turn interactive mode on.' - matplotlib.interactive(True) +draw_all = _pylab_helpers.Gcf.draw_all -def pause(interval): - """ - Pause for *interval* seconds. +# Ensure this appears in the pyplot docs. +@_copy_docstring_and_deprecators(matplotlib.set_loglevel) +def set_loglevel(level: LogLevel) -> None: + return matplotlib.set_loglevel(level) + - If there is an active figure it will be updated and displayed, - and the GUI event loop will run during the pause. +@_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) - If there is no active figure, or if a non-interactive backend - is in use, this executes time.sleep(interval). - This can be used for crude animation. For more complex - animation, see :mod:`matplotlib.animation`. +_backend_mod: type[matplotlib.backend_bases._Backend] | None = None - This function is experimental; its behavior may be changed - or extended in a future release. +def _get_backend_mod() -> type[matplotlib.backend_bases._Backend]: """ - 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 - - # No on-screen figure is active, so sleep() is all we need. - import time - time.sleep(interval) + Ensure that a backend is selected and return it. + This is currently private, but may be made public in the future. + """ + 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) -@docstring.copy_dedent(matplotlib.rc) -def rc(*args, **kwargs): - matplotlib.rc(*args, **kwargs) +def switch_backend(newbackend: str) -> None: + """ + Set the pyplot backend. -@docstring.copy_dedent(matplotlib.rc_context) -def rc_context(rc=None, fname=None): - return matplotlib.rc_context(rc, fname) + 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. + Parameters + ---------- + newbackend : str + The case-insensitive name of the backend to use. -@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. """ - return gcf()._gci() + 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 sci(im): +# This function's signature is rewritten upon backend-load by switch_backend. +def draw_if_interactive(*args, **kwargs): """ - 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. + 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. """ - gca()._sci(im) + return _get_backend_mod().draw_if_interactive(*args, **kwargs) -## Any Artist ## -# (getp is simply imported) -@docstring.copy(_setp) -def setp(*args, **kwargs): - ret = _setp(*args, **kwargs) - draw_if_interactive() - return ret +@overload +def show(*, block: bool, **kwargs) -> None: ... -def xkcd(scale=1, length=100, randomness=2): - """ - Turns on `xkcd `_ sketch-style drawing mode. - This will only have effect on things drawn after this function is - called. +@overload +def show(*args: Any, **kwargs: Any) -> None: ... + - For best results, the "Humor Sans" font should be installed: it is - not included with matplotlib. +# This function's signature is rewritten upon backend-load by switch_backend. +def show(*args, **kwargs) -> None: + """ + Display all open figures. Parameters ---------- - scale : float, optional - The amplitude of the wiggle perpendicular to the source line. - length : float, optional - The length of the wiggle along the line. - randomness : float, optional - The scale factor by which the length is shrunken or expanded. + 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. + + 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 ----- - This function works by a number of rcParams, so it will probably - override others you have set before. + **Saving figures to file and showing a window at the same time** - If you want the effects of this function to be temporary, it can - be used as a context manager, for example:: + 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`. - with plt.xkcd(): - # This figure will be in XKCD-style - fig1 = plt.figure() - # ... + **Auto-show in jupyter notebooks** - # This figure will be in regular style - fig2 = plt.figure() + 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. """ - if rcParams['text.usetex']: - raise RuntimeError( - "xkcd mode is not compatible with text.usetex = True") + _warn_if_gui_out_of_main_thread() + return _get_backend_mod().show(*args, **kwargs) - 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 +def isinteractive() -> bool: + """ + Return whether plots are updated after every plotting command. -## Figures ## + 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. -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 - ): - """ - Creates a new figure. + In interactive mode: - Parameters - ---------- + - newly created figures will be shown immediately; + - figures will automatically redraw on change; + - `.pyplot.show` will not block by default. - 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`. + In non-interactive mode: - figsize : tuple of integers, optional, default: None - width, height in inches. If not provided, defaults to rc - figure.figsize. + - newly created figures and changes to figures will not be reflected until + explicitly asked to be; + - `.pyplot.show` will block by default. - dpi : integer, optional, default: None - resolution of the figure. If not provided, defaults to rc figure.dpi. + 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. + """ + return matplotlib.is_interactive() - facecolor : - the background color. If not provided, defaults to rc figure.facecolor - edgecolor : - the border color. If not provided, defaults to rc figure.edgecolor +# 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. - 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. + 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. 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 + 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 - 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'] - - allnums = get_fignums() - next_num = max(allnums) + 1 if allnums else 1 - figLabel = '' - 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 - - figManager = _pylab_helpers.Gcf.get_fig_manager(num) - if figManager is None: - max_open_warning = rcParams['figure.max_open_warning'] - 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) +# 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: + """ + Enable interactive mode. - if get_backend().lower() == 'ps': - dpi = 72 + See `.pyplot.isinteractive` for more details. - figManager = new_figure_manager(num, figsize=figsize, - dpi=dpi, - facecolor=facecolor, - edgecolor=edgecolor, - frameon=frameon, - FigureClass=FigureClass, - **kwargs) + 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. - if figLabel: - figManager.set_window_title(figLabel) - figManager.canvas.figure.set_label(figLabel) + 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() + # ... - # make this figure current on button press event - def make_active(event): - _pylab_helpers.Gcf.set_active(figManager) + 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(True) + install_repl_displayhook() + return stack - cid = figManager.canvas.mpl_connect('button_press_event', make_active) - figManager._cidgcf = cid - _pylab_helpers.Gcf.set_active(figManager) - figManager.canvas.figure.number = num +def pause(interval: float) -> None: + """ + Run the GUI event loop for *interval* seconds. - draw_if_interactive() - return figManager.canvas.figure + 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. + This can be used for crude animation. For more complex animation use + :mod:`matplotlib.animation`. -def gcf(): - "Get a reference to the current figure." + If there is no active figure, sleep for *interval* seconds instead. - figManager = _pylab_helpers.Gcf.get_active() - if figManager is not None: - return figManager.canvas.figure + 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: - return figure() + time.sleep(interval) -fignum_exists = _pylab_helpers.Gcf.has_fignum +@_copy_docstring_and_deprecators(matplotlib.rc) +def rc(group: RcGroupKeyType, **kwargs) -> None: + matplotlib.rc(group, **kwargs) -def get_fignums(): - """Return a list of existing figure numbers.""" - fignums = list(six.iterkeys(_pylab_helpers.Gcf.figs)) - fignums.sort() - return fignums +@_copy_docstring_and_deprecators(matplotlib.rc_context) +def rc_context( + rc: dict[RcKeyType, Any] | None = None, + fname: str | pathlib.Path | os.PathLike | None = None, +) -> AbstractContextManager[None]: + return matplotlib.rc_context(rc, fname) -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] +@_copy_docstring_and_deprecators(matplotlib.rcdefaults) +def rcdefaults() -> None: + matplotlib.rcdefaults() + if matplotlib.is_interactive(): + draw_all() -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 +# getp/get/setp are explicitly reexported so that they show up in pyplot docs. -@docstring.copy_dedent(FigureCanvasBase.mpl_connect) -def connect(s, func): - return get_current_fig_manager().canvas.mpl_connect(s, func) +@_copy_docstring_and_deprecators(matplotlib.artist.getp) +def getp(obj, *args, **kwargs): + return matplotlib.artist.getp(obj, *args, **kwargs) -@docstring.copy_dedent(FigureCanvasBase.mpl_disconnect) -def disconnect(cid): - return get_current_fig_manager().canvas.mpl_disconnect(cid) +@_copy_docstring_and_deprecators(matplotlib.artist.get) +def get(obj, *args, **kwargs): + return matplotlib.artist.get(obj, *args, **kwargs) -def close(*args): - """ - Close a figure window. - ``close()`` by itself closes the current figure +@_copy_docstring_and_deprecators(matplotlib.artist.setp) +def setp(obj, *args, **kwargs): + return matplotlib.artist.setp(obj, *args, **kwargs) - ``close(h)`` where *h* is a :class:`Figure` instance, closes that figure - ``close(num)`` closes figure number *num* +def xkcd( + scale: float = 1, length: float = 100, randomness: float = 2 +) -> ExitStack: + """ + Turn on `xkcd `_ sketch-style drawing mode. - ``close(name)`` where *name* is a string, closes figure with that label + This will only have an effect on things drawn after this function is called. - ``close('all')`` closes all the figure windows - """ + For best results, install the `xkcd script `_ + font; xkcd fonts are not packaged with Matplotlib. - if len(args) == 0: - figManager = _pylab_helpers.Gcf.get_active() - if figManager 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)) - else: - raise TypeError('close takes 0 or 1 arguments') + Parameters + ---------- + scale : float, optional + The amplitude of the wiggle perpendicular to the source line. + length : float, optional + The length of the wiggle along the line. + randomness : float, optional + The scale factor by which the length is shrunken or expanded. + Notes + ----- + This function works by a number of rcParams, overriding those set before. -def clf(): - """ - Clear the current figure. - """ - gcf().clf() - draw_if_interactive() + If you want the effects of this function to be temporary, it can + be used as a context manager, for example:: + with plt.xkcd(): + # This figure will be in XKCD-style + fig1 = plt.figure() + # ... -def draw(): + # This figure will be in regular style + fig2 = plt.figure() """ - Redraw the current 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") - 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`. + stack = ExitStack() + stack.callback(rcParams._update_raw, rcParams.copy()) - A more object-oriented alternative, given any - :class:`~matplotlib.figure.Figure` instance, :attr:`fig`, that - was created using a :mod:`~matplotlib.pyplot` function, is:: + from matplotlib import patheffects + 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 - fig.canvas.draw() +## Figures ## +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: """ - get_current_fig_manager().canvas.draw() + 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. -@docstring.copy_dedent(Figure.savefig) -def savefig(*args, **kwargs): - fig = gcf() - res = fig.savefig(*args, **kwargs) - draw() # need this if 'transparent=True' to reset colors - return res - + 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. -@docstring.copy_dedent(Figure.ginput) -def ginput(*args, **kwargs): - """ - Blocking call to interact with the figure. + 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. - This will wait for *n* clicks from the user and return a list of the - coordinates of each click. + If *num* is a Figure instance that is already tracked in pyplot, it is + activated. If *num* is a Figure instance that is not tracked in pyplot, + it is added to the tracked figures and activated. - If *timeout* is negative, does not timeout. - """ - return gcf().ginput(*args, **kwargs) + 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")``. -@docstring.copy_dedent(Figure.waitforbuttonpress) -def waitforbuttonpress(*args, **kwargs): - """ - Blocking call to interact with the figure. + One of *width* or *height* may be ``None``; the respective value is taken + from :rc:`figure.figsize`. - 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. + dpi : float, default: :rc:`figure.dpi` + The resolution of the figure in dots-per-inch. - If *timeout* is negative, does not timeout. - """ - return gcf().waitforbuttonpress(*args, **kwargs) + facecolor : :mpltype:`color`, default: :rc:`figure.facecolor` + The background color. + edgecolor : :mpltype:`color`, default: :rc:`figure.edgecolor` + The border color. -# Putting things in figures + frameon : bool, default: True + If False, suppress drawing the figure frame. -@docstring.copy_dedent(Figure.text) -def figtext(*args, **kwargs): + FigureClass : subclass of `~matplotlib.figure.Figure` + If set, an instance of this subclass will be created, rather than a + plain `.Figure`. - ret = gcf().text(*args, **kwargs) - draw_if_interactive() - return ret + clear : bool, default: False + If True and the figure already exists, then it is cleared. + 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. -@docstring.copy_dedent(Figure.suptitle) -def suptitle(*args, **kwargs): - ret = gcf().suptitle(*args, **kwargs) - draw_if_interactive() - return ret + - '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. -@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 + - '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. -def figlegend(handles, labels, loc, **kwargs): - """ - Place a legend in the figure. + - 'none': Do not use a layout engine. - *labels* - a sequence of strings + - 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. - *handles* - a sequence of :class:`~matplotlib.lines.Line2D` or - :class:`~matplotlib.patches.Patch` instances + 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`. - *loc* - can be a string or an integer specifying the legend - location + **kwargs + Additional keyword arguments are passed to the `.Figure` constructor. - A :class:`matplotlib.legend.Legend` instance is returned. + Returns + ------- + `~matplotlib.figure.Figure` - Example:: + Notes + ----- + 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() + next_num = max(allnums) + 1 if allnums else 1 - figlegend( (line1, line2, line3), - ('label1', 'label2', 'label3'), - 'upper right' ) + if isinstance(num, FigureBase): + # type narrowed to `Figure | SubFigure` by combination of input and isinstance + has_figure_property_parameters = ( + any(param is not None for param in [figsize, dpi, facecolor, edgecolor]) + or not frameon or kwargs + ) + + root_fig = num.get_figure(root=True) + if root_fig.canvas.manager is None: + if has_figure_property_parameters: + raise ValueError( + "You cannot pass figure properties when calling figure() with " + "an existing Figure instance") + backend = _get_backend_mod() + manager_ = backend.new_figure_manager_given_figure(next_num, root_fig) + _pylab_helpers.Gcf._set_new_active_manager(manager_) + return manager_.canvas.figure + elif has_figure_property_parameters 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 + + fig_label = '' + if num is None: + num = next_num + else: + 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 - .. seealso:: + manager = _pylab_helpers.Gcf.get_fig_manager(num) + 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() - :func:`~matplotlib.pyplot.legend` + if _REPL_DISPLAYHOOK is _ReplDisplayHook.PLAIN: + fig.stale_callback = _auto_draw_if_interactive - """ - l = gcf().legend(handles, labels, loc, **kwargs) - draw_if_interactive() - return l + if clear: + manager.canvas.figure.clear() + return manager.canvas.figure -## Figure and Axes hybrid ## -def hold(b=None): +def _auto_draw_if_interactive(fig, val): """ - Set the hold state. If *b* is None (default), toggle the - hold state, else set the hold state to boolean value *b*:: + An internal helper function for making sure that auto-redrawing + works as intended in the plain python repl. - hold() # toggle hold - hold(True) # hold is on - hold(False) # hold is off + 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. - 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. + 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() - fig = gcf() - ax = fig.gca() - fig.hold(b) - ax.hold(b) +def fignum_exists(num: int | str) -> bool: + """ + Return whether the figure with the given id exists. - # 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() + Parameters + ---------- + num : int or str + A figure identifier. - rc('axes', hold=b) + 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 ishold(): +def _raise_if_figure_exists(num, func_name, clear=False): """ - Return the hold status of the current axes. + Raise a ValueError if the figure *num* already exists. """ - return gca().ishold() + if num is not None and not clear: + if isinstance(num, FigureBase): + raise ValueError( + f"num {num!r} cannot be a FigureBase instance. " + f"plt.{func_name}() is for creating new figures. " + f"To add to an existing figure, use fig.{func_name}() " + "instead.") + + if fignum_exists(num): + raise ValueError( + f"Figure {num!r} already exists. Use plt.figure({num!r}) " + f"to get it or plt.close({num!r}) to close it. " + f"Alternatively, pass 'clear=True' to {func_name}().") + + +def get_fignums() -> list[int]: + """Return a list of existing figure numbers.""" + return sorted(_pylab_helpers.Gcf.figs) -def over(func, *args, **kwargs): +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] + + +def get_current_fig_manager() -> FigureManagerBase | None: """ - Call a function with hold(True). + Return the figure manager of the current figure. - Calls:: + The figure manager is a container for the actual backend-depended window + that displays the figure on screen. - func(*args, **kwargs) + If no current figure exists, a new one is created, and its figure + manager is returned. - with ``hold(True)`` and then restores the hold state. + Returns + ------- + `.FigureManagerBase` or backend-dependent subclass thereof """ - h = ishold() - hold(True) - func(*args, **kwargs) - hold(h) + return gcf().canvas.manager -## Axes ## +@overload +def connect(s: MouseEventType, func: Callable[[MouseEvent], Any]) -> int: ... -def axes(*args, **kwargs): - """ - Add an axes to the figure. - The axes is added at position *rect* specified by: +@overload +def connect(s: KeyEventType, func: Callable[[KeyEvent], Any]) -> int: ... - - ``axes()`` by itself creates a default full ``subplot(111)`` window axis. - - ``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. +@overload +def connect(s: PickEventType, func: Callable[[PickEvent], Any]) -> int: ... - - ``axes(h)`` where *h* is an axes instance makes *h* the current - axis. An :class:`~matplotlib.axes.Axes` instance is returned. - ======= ============== ============================================== - 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`. - ======= ============== ============================================== +@overload +def connect(s: ResizeEventType, func: Callable[[ResizeEvent], Any]) -> int: ... - Examples: - * :file:`examples/pylab_examples/axes_demo.py` places custom axes. - * :file:`examples/pylab_examples/shared_axis_demo.py` uses - *sharex* and *sharey*. +@overload +def connect(s: CloseEventType, func: Callable[[CloseEvent], Any]) -> int: ... - """ - nargs = len(args) - if len(args) == 0: - return subplot(111, **kwargs) - if nargs > 1: - raise TypeError('Only one non keyword arg to axes allowed') - arg = args[0] +@overload +def connect(s: DrawEventType, func: Callable[[DrawEvent], Any]) -> int: ... - if isinstance(arg, Axes): - a = gcf().sca(arg) - else: - rect = arg - a = gcf().add_axes(rect, **kwargs) - draw_if_interactive() - return a +@_copy_docstring_and_deprecators(FigureCanvasBase.mpl_connect) +def connect(s, func) -> int: + return gcf().canvas.mpl_connect(s, func) -def delaxes(*args): - """ - Remove an axes from the current figure. If *ax* - doesn't exist, an error will be raised. - ``delaxes()``: delete the current axes - """ - if not len(args): - ax = gca() - else: - ax = args[0] - ret = gcf().delaxes(ax) - draw_if_interactive() - return ret +@_copy_docstring_and_deprecators(FigureCanvasBase.mpl_disconnect) +def disconnect(cid: int) -> None: + gcf().canvas.mpl_disconnect(cid) -def sca(ax): +def close(fig: None | int | str | Figure | Literal["all"] = None) -> None: """ - Set the current Axes instance to *ax*. + Close a figure window, and unregister it from pyplot. + + Parameters + ---------- + fig : None or int or str or `.Figure` + The figure to close. There are a number of ways to specify this: - The current Figure is updated to the parent of *ax*. + - *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()`. """ - 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) + if fig is None: + manager = _pylab_helpers.Gcf.get_active() + if manager is None: return - raise ValueError("Axes instance argument was not found in a figure.") + else: + _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: + _api.check_isinstance( # type: ignore[unreachable] + (Figure, int, str, None), fig=fig) -def gca(**kwargs): - """ - Get the current :class:`~matplotlib.axes.Axes` instance on the - current figure matching the given keyword args, or create one. +def clf() -> None: + """Clear the current figure.""" + gcf().clear() - Examples - --------- - To get the current polar axes on the current figure:: - plt.gca(projection='polar') +def draw() -> None: + """ + Redraw the current figure. + + 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. - If the current axes doesn't exist, or isn't a polar one, the appropriate - axes will be created and then returned. + This is equivalent to calling ``fig.canvas.draw_idle()``, where ``fig`` is + the current figure. See Also -------- - matplotlib.figure.Figure.gca : The figure's gca method. + .FigureCanvasBase.draw_idle + .FigureCanvasBase.draw """ - ax = gcf().gca(**kwargs) - return ax + gcf().canvas.draw_idle() -# More ways of creating axes: -def subplot(*args, **kwargs): - """ - Return a subplot axes positioned by the given grid definition. +@_copy_docstring_and_deprecators(Figure.savefig) +def savefig(fname: str | os.PathLike | IO, **kwargs) -> None: + fig = gcf() + # savefig default implementation has no return, so mypy is unhappy + # presumably this is here because subclasses can return? + res = fig.savefig(fname, **kwargs) # type: ignore[func-returns-value] + fig.canvas.draw_idle() # Need this if 'transparent=True', to reset colors. + return res - Typical call signature:: - subplot(nrows, ncols, plot_number) +## Putting things in figures ## - 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``. - 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:: +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(") - subplot(211) - 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). +## Axes ## - .. note:: +@_docstring.interpd +def axes( + arg: None | tuple[float, float, float, float] = None, + **kwargs +) -> matplotlib.axes.Axes: + """ + Add an Axes to the current figure and make it the current Axes. - Creating a new subplot with a position which is entirely inside a - pre-existing axes will trigger the larger axes to be deleted:: + Call signatures:: - 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 + plt.axes() + plt.axes(rect, projection=None, polar=False, **kwargs) + plt.axes(ax) - If you do not want this behavior, use the - :meth:`~matplotlib.figure.Figure.add_subplot` method or the - :func:`~matplotlib.pyplot.axes` function instead. + Parameters + ---------- + arg : None or 4-tuple + The exact behavior of this function depends on the type: - Keyword arguments: + - *None*: A new full window Axes is added using + ``subplot(**kwargs)``. + - 4-tuple of float *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. - *axisbg*: - The background color of the subplot, which can be any valid - color specifier. See :mod:`matplotlib.colors` for more - information. + 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. - *polar*: - A boolean flag indicating whether the subplot plot should be - a polar projection. Defaults to *False*. + polar : bool, default: False + If True, equivalent to projection='polar'. - *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`. + 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. - .. seealso:: + label : str + A label for the returned Axes. - :func:`~matplotlib.pyplot.axes` - For additional information on :func:`axes` and - :func:`subplot` keyword arguments. + 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. - :file:`examples/pie_and_polar_charts/polar_scatter_demo.py` - For an example + 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. - **Example:** + %(Axes:kwdoc)s - .. plot:: mpl_examples/subplots_axes_and_figures/subplot_demo.py + See Also + -------- + .Figure.add_axes + .pyplot.subplot + .Figure.add_subplot + .Figure.subplots + .pyplot.subplots - """ - # if subplot called without arguments, create subplot(1,1,1) - if len(args)==0: - args=(1,1,1) + Examples + -------- + :: - # 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()?") + # Creating a new full window Axes + plt.axes() + # Creating a new Axes with specified dimensions and a grey background + plt.axes((left, bottom, width, height), facecolor='grey') + """ 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) + 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) + - draw_if_interactive() - return a +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() -def subplots(nrows=1, ncols=1, sharex=False, sharey=False, squeeze=True, - subplot_kw=None, gridspec_kw=None, **fig_kw): +def sca(ax: Axes) -> None: """ - Create a figure with a set of subplots already made. + 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) + fig.sca(ax) # type: ignore[union-attr] - This utility wrapper makes it convenient to create common layouts of - subplots, including the enclosing figure object, in a single call. - 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. +def cla() -> None: + """Clear the current Axes.""" + # Not generated via boilerplate.py to allow a different docstring. + return gca().cla() - *gridspec_kw* : dict - Dict with keywords passed to the - :class:`~matplotlib.gridspec.GridSpec` constructor used to create - the grid the subplots are placed on. - *fig_kw* : dict - Dict with keywords passed to the :func:`figure` call. Note that all - keywords not recognized above will be automatically included here. +## More ways of creating Axes ## - Returns: +@overload +def subplot(nrows: int, ncols: int, index: int, /, **kwargs): ... - fig, ax : tuple - - *fig* is the :class:`matplotlib.figure.Figure` object +@overload +def subplot(pos: int | SubplotSpec, /, **kwargs): ... - - *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. - Examples:: +@overload +def subplot(**kwargs): ... - x = np.linspace(0, 2*np.pi, 400) - y = np.sin(x**2) - # Just a figure and one subplot - f, ax = plt.subplots() - ax.plot(x, y) - ax.set_title('Simple plot') +@_docstring.interpd +def subplot(*args, **kwargs) -> Axes: + """ + Add an Axes to the current figure or retrieve an existing Axes. - # 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) + This is a wrapper of `.Figure.add_subplot` which provides additional + behavior when working with the implicit API (see the notes section). - # Four polar axes - plt.subplots(2, 2, subplot_kw=dict(polar=True)) + Call signatures:: - # Share a X axis with each column of subplots - plt.subplots(2, 2, sharex='col') + subplot(nrows, ncols, index, **kwargs) + subplot(pos, **kwargs) + subplot(**kwargs) - # Share a Y axis with each row of subplots - plt.subplots(2, 2, sharey='row') + 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. - # 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 = {} + label : str + A label for the returned Axes. - 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) + Returns + ------- + `~.axes.Axes` - return ret + The Axes of the subplot. The returned Axes can actually be an instance + of a subclass, such as `.projections.polar.PolarAxes` for polar + projections. + + 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. + %(Axes:kwdoc)s -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 + ----- + .. 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. - subplot2grid(shape, loc, rowspan=1, colspan=1) + See Also + -------- + .Figure.add_subplot + .pyplot.subplots + .pyplot.axes + .Figure.subplots - is identical to :: + Examples + -------- + :: + + plt.subplot(221) + + # equivalent but more general + ax1 = plt.subplot(2, 2, 1) + + # add a subplot with no frame + ax2 = plt.subplot(222, frameon=False) + + # add a polar subplot + plt.subplot(223, projection='polar') + + # add a red subplot that shares the x-axis with ax1 + plt.subplot(224, sharex=ax1, facecolor='red') + + # delete ax2 from the figure + plt.delaxes(ax2) + + # add ax2 to the figure again + plt.subplot(ax2) + + # make the first Axes "current" again + plt.subplot(221) - gridspec=GridSpec(shape[0], shape[1]) - subplotspec=gridspec.new_subplotspec(loc, rowspan, colspan) - subplot(subplotspec) """ + # 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' + + # if subplot called without arguments, create subplot(1, 1, 1) + if len(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()?") 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 + # 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: + # we have exhausted the known Axes and none match, make a new one! + ax = fig.add_subplot(*args, **kwargs) + fig.sca(ax) -def twinx(ax=None): - """ - 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. + return ax - .. seealso:: - :file:`examples/api_examples/two_scales.py` - For an example +@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: Any +) -> 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: Any +) -> 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: Any +) -> 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: Any +) -> tuple[Figure, Any]: """ - if ax is None: - ax=gca() - ax1 = ax.twinx() - draw_if_interactive() - return ax1 + 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 twiny(ax=None): - """ - 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. - """ - if ax is None: - ax=gca() - ax1 = ax.twiny() - draw_if_interactive() - return ax1 + 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. + gridspec_kw : dict, optional + Dict with keywords passed to the `~matplotlib.gridspec.GridSpec` + constructor used to create the grid the subplots are placed on. -def subplots_adjust(*args, **kwargs): - """ - Tune the subplot layout. + **fig_kw + All additional keyword arguments are passed to the + `.pyplot.figure` call. - call signature:: + Returns + ------- + fig : `.Figure` - subplots_adjust(left=None, bottom=None, right=None, top=None, - wspace=None, hspace=None) + 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. - The parameter meanings (and suggested defaults) are:: + Typical idioms for handling the return value 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 + # using the variable ax for a single Axes + fig, ax = plt.subplots() - The actual defaults are controlled by the rc file - """ - fig = gcf() - fig.subplots_adjust(*args, **kwargs) - draw_if_interactive() + # using the variable axs for multiple Axes + fig, axs = plt.subplots(2, 2) + # using tuple unpacking for multiple Axes + fig, (ax1, ax2) = plt.subplots(1, 2) + fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2) -def subplot_tool(targetfig=None): - """ - Launch a subplot tool window for a figure. + 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. - A :class:`matplotlib.widgets.SubplotTool` instance is returned. - """ - 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 - 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 + See Also + -------- + .pyplot.figure + .pyplot.subplot + .pyplot.axes + .Figure.subplots + .Figure.add_subplot + + Examples + -------- + :: + # First create some toy data: + x = np.linspace(0, 2*np.pi, 400) + y = np.sin(x**2) -def tight_layout(pad=1.08, h_pad=None, w_pad=None, rect=None): - """ - Automatically adjust subplot parameters to give specified padding. + # Create just a figure and only one subplot + fig, ax = plt.subplots() + ax.plot(x, y) + ax.set_title('Simple plot') - Parameters: + # 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) - 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). - """ + # 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) - fig = gcf() - fig.tight_layout(pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect) - draw_if_interactive() + # Share an X axis with each column of subplots + plt.subplots(2, 2, sharex='col') + # Share a Y axis with each row of subplots + plt.subplots(2, 2, sharey='row') -def box(on=None): - """ - Turn the axes box on or off. *on* may be a boolean or a string, - 'on' or 'off'. + # Share both X and Y axes with all subplots + plt.subplots(2, 2, sharex='all', sharey='all') - If *on* is *None*, toggle state. - """ - 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() + # Note that this is the same as + plt.subplots(2, 2, sharex=True, sharey=True) + + # Create figure number 10 with a single subplot + # and clears it if it already exists. + fig, ax = plt.subplots(num=10, clear=True) + """ + num = fig_kw.get('num') + _raise_if_figure_exists(fig_kw.get('num'), "subplots", fig_kw.get('clear')) -def title(s, *args, **kwargs): + 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]]: """ - Set a title of the current axes. + Build a layout of Axes based on ASCII art or nested lists. - 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. + This is a helper function to build complex GridSpec layouts visually. - .. seealso:: - See :func:`~matplotlib.pyplot.text` for adding text - to the current axes + See :ref:`mosaic` + for an example and full API documentation Parameters ---------- - label : str - Text to use for the title + mosaic : list of list of {hashable or nested} or str - fontdict : dict - A dictionary controlling the appearance of the title text, - the default `fontdict` is: + A visual layout of how you want your Axes to be arranged + labeled as strings. For example :: - {'fontsize': rcParams['axes.titlesize'], - 'fontweight' : rcParams['axes.titleweight'], - 'verticalalignment': 'baseline', - 'horizontalalignment': loc} + x = [['A panel', 'A panel', 'edge'], + ['C panel', '.', 'edge']] - loc : {'center', 'left', 'right'}, str, optional - Which title to set, defaults to 'center' + produces 4 Axes: - Returns - ------- - text : :class:`~matplotlib.text.Text` - The matplotlib text instance representing the title + - '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 - Other parameters - ---------------- - kwargs : text properties - Other keyword arguments are text properties, see - :class:`~matplotlib.text.Text` for a list of valid text - properties. + Any of the entries in the layout can be a list of lists + of the same form to create nested layouts. - """ - l = gca().set_title(s, *args, **kwargs) - draw_if_interactive() - return l + If input is a str, then it must be of the form :: -## Axis ## + ''' + AAE + C.E + ''' + 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. -def axis(*v, **kwargs): - """ - Convenience method to get or set axis properties. + 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. - Calling with no arguments:: + 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': [...]}``. - >>> axis() + 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': [...]}``. - returns the current axes limits ``[xmin, xmax, ymin, ymax]``.:: + 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. - >>> axis(v) + 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*. - sets the min and max of the x and y axes, with - ``v = [xmin, xmax, ymin, ymax]``.:: + 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*. - >>> axis('off') + 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")``. - turns off the axis lines and labels.:: + .. versionadded:: 3.7 - >>> axis('equal') + gridspec_kw : dict, optional + Dictionary with keywords passed to the `.GridSpec` constructor used + to create the grid the subplots are placed on. - changes limits of *x* or *y* axis so that equal increments of *x* - and *y* have the same length; a circle is circular.:: + **fig_kw + All additional keyword arguments are passed to the + `.pyplot.figure` call. - >>> axis('scaled') + Returns + ------- + fig : `.Figure` + The new figure - achieves the same result by changing the dimensions of the plot box instead - of the axis data limits.:: + 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. - >>> axis('tight') + """ + num = fig_kw.get('num') + _raise_if_figure_exists(fig_kw.get('num'), "subplot_mosaic", fig_kw.get('clear')) - 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.:: + fig = figure(**fig_kw) + 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. - >>> axis('image') + 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`. - is 'scaled' with the axis limits equal to the data limits.:: + Returns + ------- + `~.axes.Axes` - >>> axis('auto') + The Axes of the subplot. The returned Axes can actually be an instance + of a subclass, such as `.projections.polar.PolarAxes` for polar + projections. - and:: + Notes + ----- + The following call :: - >>> axis('normal') + ax = subplot2grid((nrows, ncols), (row, col), rowspan, colspan) - are deprecated. They restore default behavior; axis limits are automatically - scaled to make the data fit comfortably within the plot box. + is identical to :: - if ``len(*v)==0``, you can pass in *xmin*, *xmax*, *ymin*, *ymax* - as kwargs selectively to alter just those limits without changing - the others. + fig = gcf() + gs = fig.add_gridspec(nrows, ncols) + ax = fig.add_subplot(gs[row:row+rowspan, col:col+colspan]) + """ + 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) - The xmin, xmax, ymin, ymax tuple is returned - .. seealso:: +def twinx(ax: matplotlib.axes.Axes | None = None) -> _AxesBase: + """ + 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. - :func:`xlim`, :func:`ylim` - For setting the x- and y-limits individually. + Examples + -------- + :doc:`/gallery/subplots_axes_and_figures/two_scales` """ - ax = gca() - v = ax.axis(*v, **kwargs) - draw_if_interactive() - return v + if ax is None: + ax = gca() + ax1 = ax.twinx() + return ax1 -def xlabel(s, *args, **kwargs): +def twiny(ax: matplotlib.axes.Axes | None = None) -> _AxesBase: + """ + 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` """ - Set the *x* axis label of the current axis. + if ax is None: + ax = gca() + ax1 = ax.twiny() + return ax1 - Default override is:: - override = { - 'fontsize' : 'small', - 'verticalalignment' : 'top', - 'horizontalalignment' : 'center' - } +def subplot_tool(targetfig: Figure | None = None) -> SubplotTool | None: + """ + Launch a subplot tool window for a figure. + + Returns + ------- + `matplotlib.widgets.SubplotTool` + """ + if targetfig is None: + 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: + raise ValueError("subplot_tool can only be launched for figures with " + "an associated toolbar") - .. seealso:: - :func:`~matplotlib.pyplot.text` - For information on how override and the optional args work +def box(on: bool | None = None) -> None: """ - l = gca().set_xlabel(s, *args, **kwargs) - draw_if_interactive() - return l + Turn the Axes box on or off on the current Axes. + Parameters + ---------- + on : bool or None + The new `~matplotlib.axes.Axes` box state. If ``None``, toggle + the state. -def ylabel(s, *args, **kwargs): + See Also + -------- + :meth:`matplotlib.axes.Axes.set_frame_on` + :meth:`matplotlib.axes.Axes.get_frame_on` """ - Set the *y* axis label of the current axis. + ax = gca() + if on is None: + on = not ax.get_frame_on() + ax.set_frame_on(on) - Defaults override is:: +## Axis ## - override = { - 'fontsize' : 'small', - 'verticalalignment' : 'center', - 'horizontalalignment' : 'right', - 'rotation'='vertical' : } - .. seealso:: +@overload +def xlim() -> tuple[float, float]: + ... - :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 +@overload +def xlim( + left: float | tuple[float, float] | None = None, + right: float | None = None, + *, + emit: bool = True, + auto: bool | None = False, + xmin: float | None = None, + xmax: float | None = None, +) -> tuple[float, float]: + ... -def xlim(*args, **kwargs): + +def xlim(*args, **kwargs) -> tuple[float, float]: """ - Get or set the *x* limits of the current axes. + Get or set the x limits of the current Axes. - :: + Call signatures:: - 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 + 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 - If you do not specify args, you can pass the xmin and xmax as - kwargs, e.g.:: + If you do not specify args, you can pass *left* or *right* as kwargs, + i.e.:: - xlim(xmax=3) # adjust the max leaving min unchanged - xlim(xmin=1) # adjust the min leaving max unchanged + xlim(right=3) # adjust the right leaving left unchanged + xlim(left=1) # adjust the left leaving right unchanged Setting limits turns autoscaling off for the x-axis. - The new axis limits are returned as a length 2 tuple. + Returns + ------- + 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. """ ax = gca() if not args and not kwargs: return ax.get_xlim() ret = ax.set_xlim(*args, **kwargs) - draw_if_interactive() return ret -def ylim(*args, **kwargs): +@overload +def ylim() -> tuple[float, float]: + ... + + +@overload +def ylim( + bottom: float | tuple[float, float] | None = None, + top: float | None = None, + *, + emit: bool = True, + auto: bool | None = False, + ymin: float | None = None, + ymax: float | None = None, +) -> tuple[float, float]: + ... + + +def ylim(*args, **kwargs) -> tuple[float, float]: """ - Get or set the *y*-limits of the current axes. + Get or set the y-limits of the current Axes. - :: + Call signatures:: - 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 + 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 - If you do not specify args, you can pass the *ymin* and *ymax* as - kwargs, e.g.:: + If you do not specify args, you can alternatively pass *bottom* or + *top* as kwargs, i.e.:: - ylim(ymax=3) # adjust the max leaving min unchanged - ylim(ymin=1) # adjust the min leaving max unchanged + ylim(top=3) # adjust the top leaving bottom unchanged + ylim(bottom=1) # adjust the bottom leaving top unchanged Setting limits turns autoscaling off for the y-axis. - The new axis limits are returned as a length 2 tuple. + Returns + ------- + bottom, top + A tuple of the new y-axis limits. + + 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) - draw_if_interactive() return ret -@docstring.dedent_interpd -def xscale(*args, **kwargs): +def xticks( + ticks: ArrayLike | None = None, + labels: Sequence[str] | None = None, + *, + minor: bool = False, + **kwargs +) -> tuple[list[Tick] | np.ndarray, list[Text]]: """ - Set the scaling of the *x*-axis. - - call signature:: + Get or set the current tick locations and labels of the x-axis. - xscale(scale, **kwargs) + Pass no arguments to return the current values without modifying them. - The available scales are: %(scale)s - - Different keywords may be accepted, depending on the scale: + 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. - %(scale_docs)s - """ - ax = gca() - ax.set_xscale(*args, **kwargs) - draw_if_interactive() + .. 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. -@docstring.dedent_interpd -def yscale(*args, **kwargs): - """ - Set the scaling of the *y*-axis. + 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). - call signature:: + Use `~.pyplot.tick_params` instead if possible. - yscale(scale, **kwargs) - The available scales are: %(scale)s + Returns + ------- + locs + The list of xtick locations. + labels + The list of xlabel `.Text` objects. - Different keywords may be accepted, depending on the scale: + 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. - %(scale_docs)s + 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() - ax.set_yscale(*args, **kwargs) - draw_if_interactive() + 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) -def xticks(*args, **kwargs): - """ - Get or set the *x*-limits of the current tick locations and labels. + 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) - :: + return locs, labels_out + + +def yticks( + 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 y-axis. - # return locs, labels where locs is an array of tick locations and - # labels is an array of tick labels. - locs, labels = xticks() + Pass no arguments to return the current values without modifying them. - # set the locations of the xticks - xticks( arange(6) ) + 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. - # set the locations and labels of the xticks - xticks( arange(5), ('Tom', 'Dick', 'Harry', 'Sally', 'Sue') ) + Returns + ------- + locs + The list of ytick locations. + labels + The list of ylabel `.Text` objects. - The keyword args, if any, are :class:`~matplotlib.text.Text` - properties. For example, to rotate long labels:: + 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. - xticks( arange(12), calendar.month_name[1:13], rotation=17 ) + 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. """ ax = gca() - 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) + 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) + + 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) - draw_if_interactive() - return locs, silent_list('Text xticklabel', labels) + return locs, labels_out -def yticks(*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 *y*-limits of the current tick locations and labels. + Get or set the radial gridlines on the current polar plot. - :: + Call signatures:: - # return locs, labels where locs is an array of tick locations and - # labels is an array of tick labels. - locs, labels = yticks() + lines, labels = rgrids() + lines, labels = rgrids(radii, labels=None, angle=22.5, fmt=None, **kwargs) - # set the locations of the yticks - yticks( arange(6) ) + 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. - # set the locations and labels of the yticks - yticks( arange(5), ('Tom', 'Dick', 'Harry', 'Sally', 'Sue') ) + Parameters + ---------- + radii : tuple with floats + The radii for the radial gridlines - The keyword args, if any, are :class:`~matplotlib.text.Text` - properties. For example, to rotate long labels:: + labels : tuple with strings or None + The labels to use at each radial gridline. The + `matplotlib.ticker.ScalarFormatter` will be used if None. - yticks( arange(12), calendar.month_name[1:13], rotation=45 ) - """ - ax = gca() + angle : float + The angular position of the radius labels in degrees. - 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) + fmt : str or None + Format string used in `matplotlib.ticker.FormatStrFormatter`. + For example '%f'. - draw_if_interactive() + Returns + ------- + lines : list of `.lines.Line2D` + The radial gridlines. - return ( locs, - silent_list('Text yticklabel', labels) - ) + labels : list of `.text.Text` + The tick labels. + Other Parameters + ---------------- + **kwargs + *kwargs* are optional `.Text` properties for the labels. -def minorticks_on(): - """ - Display minor ticks on the current plot. + See Also + -------- + .pyplot.thetagrids + .projections.polar.PolarAxes.set_rgrids + .Axis.get_gridlines + .Axis.get_ticklabels - Displaying minor ticks reduces performance; turn them off using - minorticks_off() if drawing speed is a problem. - """ - gca().minorticks_on() - draw_if_interactive() + Examples + -------- + :: + # set the locations of the radial gridlines + lines, labels = rgrids( (0.25, 0.5, 1.0) ) -def minorticks_off(): + # set the locations and labels of the radial gridlines + lines, labels = rgrids( (0.25, 0.5, 1.0), ('Tom', 'Dick', 'Harry' )) """ - Remove minor ticks from the current plot. - """ - gca().minorticks_off() - draw_if_interactive() + ax = gca() + 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 -def rgrids(*args, **kwargs): +def thetagrids( + angles: ArrayLike | None = None, + labels: Sequence[str | Text] | None = None, + fmt: str | None = None, + **kwargs +) -> tuple[list[Line2D], list[Text]]: """ - Get or set the radial gridlines on a polar plot. + Get or set the theta gridlines on the current polar plot. - call signatures:: + Call signatures:: - lines, labels = rgrids() - lines, labels = rgrids(radii, labels=None, angle=22.5, **kwargs) + lines, labels = thetagrids() + lines, labels = thetagrids(angles, labels=None, fmt=None, **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. + When called with no arguments, `.thetagrids` simply returns the tuple + (*lines*, *labels*). When called with arguments, the labels will + appear at the specified angles. - *labels*, if not *None*, is a len(*radii*) list of strings of the - labels to use at each angle. + Parameters + ---------- + angles : tuple with floats, degrees + The angles of the theta gridlines. - If *labels* is None, the rformatter will be used + labels : tuple with strings or None + The labels to use at each radial gridline. The + `.projections.polar.ThetaFormatter` will be used if None. - Examples:: + fmt : str or None + Format string used in `matplotlib.ticker.FormatStrFormatter`. + For example '%f'. Note that the angle in radians will be used. - # 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' ) - - """ - 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) ) - - -def thetagrids(*args, **kwargs): - """ - 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() - - Otherwise the syntax is:: - - lines, labels = thetagrids(angles, labels=None, fmt='%d', frac = 1.1) - - set the angles at which to place the theta grids (these gridlines - are equal along the theta dimension). - - *angles* is in degrees. - - *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. - - Return value is a list of tuples (*lines*, *labels*): + Returns + ------- + lines : list of `.lines.Line2D` + The theta gridlines. - - *lines* are :class:`~matplotlib.lines.Line2D` instances + labels : list of `.text.Text` + The tick labels. - - *labels* are :class:`~matplotlib.text.Text` instances. + Other Parameters + ---------------- + **kwargs + *kwargs* are optional `.Text` properties for the labels. - 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. + See Also + -------- + .pyplot.rgrids + .projections.polar.PolarAxes.set_thetagrids + .Axis.get_gridlines + .Axis.get_ticklabels - Examples:: + Examples + -------- + :: - # set the locations of the radial gridlines and labels - lines, labels = thetagrids( range(45,360,90) ) + # set the locations of the angular gridlines + lines, labels = thetagrids(range(45, 360, 90)) - # set the locations and labels of the radial gridlines and labels - lines, labels = thetagrids( range(45,360,90), ('NE', 'NW', 'SW','SE') ) + # set the locations and labels of the angular gridlines + 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() + 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, labels = ax.set_thetagrids(*args, **kwargs) - - draw_if_interactive() - return (silent_list('Line2D thetagridline', lines), - silent_list('Text thetagridlabel', labels) - ) - - -## Plotting Info ## + lines_out, labels_out = ax.set_thetagrids(angles, + labels=labels, fmt=fmt, + **kwargs) + return lines_out, labels_out -def plotting(): - pass - -def get_plot_commands(): +@_api.deprecated("3.7", pending=True) +def get_plot_commands() -> list[str]: """ 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 - - exclude = set(['colormaps', 'colors', 'connect', 'disconnect', - 'get_plot_commands', 'get_current_fig_manager', - 'ginput', 'plotting', 'waitforbuttonpress']) - exclude |= set(colormaps()) + 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) - 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) - - commands = list(commands) - commands.sort() - return commands - -def colors(): - """ - 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 - - ===== ======= - 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) ## Plotting part 1: manually generated functions and wrappers ## -def colorbar(mappable=None, cax=None, ax=None, **kw): + +@_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: @@ -2152,31 +2678,22 @@ def colorbar(mappable=None, cax=None, ax=None, **kw): 'creation. First define a mappable such as ' 'an image (with imshow) or a contour set (' 'with contourf).') - if ax is None: - ax = gca() - - ret = gcf().colorbar(mappable, cax = cax, ax=ax, **kw) - draw_if_interactive() + ret = gcf().colorbar(mappable, cax=cax, ax=ax, **kwargs) return ret -colorbar.__doc__ = matplotlib.colorbar.colorbar_doc -def clim(vmin=None, vmax=None): +def clim(vmin: float | None = None, vmax: float | None = None) -> None: """ Set the color limits of the current image. - To apply clim to all axes images do:: - - clim(0, 0.5) - If either *vmin* or *vmax* is None, the image min/max respectively will be used for color scaling. - If you want to set the clim of multiple images, - use, for example:: + 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.05) + im.set_clim(0, 0.5) """ im = gci() @@ -2184,21 +2701,52 @@ def clim(vmin=None, vmax=None): raise RuntimeError('You must first define an image, e.g., with imshow') im.set_clim(vmin, vmax) - draw_if_interactive() -def set_cmap(cmap): +def get_cmap(name: Colormap | str | None = None, lut: int | None = None) -> Colormap: """ - Set the default colormap. Applies to the current image if any. - See help(colormaps) for more information. + Get a colormap instance, defaulting to rc values if *name* is None. - *cmap* must be a :class:`~matplotlib.colors.Colormap` instance, or - the name of a registered colormap. + 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. + + Returns + ------- + Colormap + """ + 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) - See :func:`matplotlib.cm.register_cmap` and - :func:`matplotlib.cm.get_cmap`. + +def set_cmap(cmap: Colormap | str) -> None: """ - cmap = cm.get_cmap(cmap) + 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. + + See Also + -------- + colormaps + get_cmap + """ + cmap = get_cmap(cmap) rc('image', cmap=cmap.name) im = gci() @@ -2206,1606 +2754,2081 @@ def set_cmap(cmap): if im is not None: im.set_cmap(cmap) - draw_if_interactive() - -@docstring.copy_dedent(_imread) -def imread(*args, **kwargs): - return _imread(*args, **kwargs) +@_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) -@docstring.copy_dedent(_imsave) -def imsave(*args, **kwargs): - return _imsave(*args, **kwargs) +@_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 matshow(A, fignum=None, **kw): +def matshow(A: ArrayLike, fignum: None | int = None, **kwargs) -> AxesImage: """ - Display an array as a matrix in a new figure window. + Display a 2D 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. + 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: + + .. code-block:: none + + A[0, 0] ⋯ A[0, M-1] + ⋮ ⋮ + A[N-1, 0] ⋯ A[N-1, M-1] + + 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. + Parameters + ---------- + A : 2D array-like + The matrix to be displayed. + + fignum : None or int + If *None*, create a new, appropriately sized figure window. + + If 0, use the current Axes (creating one if there is none, without ever + adjusting the figure size). + + 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. + Returns + ------- + `~matplotlib.image.AxesImage` - *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. + Other Parameters + ---------------- + **kwargs : `~matplotlib.axes.Axes.imshow` arguments - If *fignum* is *False* or 0, a new figure window will **NOT** be created. """ A = np.asanyarray(A) - if fignum is False or fignum is 0: + if fignum == 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) + 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) - - draw_if_interactive() return im -def polar(*args, **kwargs): +def polar(*args, **kwargs) -> list[Line2D]: """ 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`. - - """ - ax = gca(polar=True) - ret = ax.plot(*args, **kwargs) - draw_if_interactive() - return ret - - -def plotfile(fname, cols=(0,), plotfuncs=None, - comments='#', skiprows=0, checkrows=5, delimiter=',', - names=None, subplots=True, newfig=True, **kwargs): - """ - 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'``. - - - 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*. + polar(theta, r, [fmt], **kwargs) - *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. + 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``. - *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. + .. 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. """ - - 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) + # 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: - 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() + ax = axes(projection="polar") + return ax.plot(*args, **kwargs) -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 +# 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) +# fmt: on ################# REMAINING CONTENT GENERATED BY boilerplate.py ############## -# 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) - - return ret - -# 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) - - return ret - -# 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) - - return ret - -# 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) - - return ret - -# 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) - - return ret - -# 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) - - return ret - -# 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) - - return ret - -# 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) - - return ret - -# 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) - - return ret - -# 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) - - return ret - -# 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) - - return ret - -# 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) - - return ret - -# 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 - -# 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 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() - - 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) - - 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() - - 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 +# 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() -# 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 +# 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[Any, Any], + xytext: tuple[Any, Any] | 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], + align: Literal["bottom", "center", "top"] = "bottom", + *, + data=None, + **kwargs, +) -> PolyCollection: + return gca().broken_barh( + xranges, + yrange, + 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.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() -# 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) +# 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() - 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() +# 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, + wedge_labels: str | Sequence | None = None, + wedge_label_distance: float | Sequence = 0.6, + autopct: str | Callable[[float], str] | None = None, + pctdistance: float = 0.6, + shadow: bool = False, + labeldistance: float | None | _Unset = _UNSET, + 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, +) -> PieContainer: + return gca().pie( + x, + explode=explode, + labels=labels, + colors=colors, + wedge_labels=wedge_labels, + wedge_label_distance=wedge_label_distance, + 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.pie_label) +def pie_label( + container: PieContainer, + /, + labels: str | Sequence[str], + *, + distance: float = 0.6, + textprops: dict | None = None, + rotate: bool = False, + alignment: str = "auto", +) -> list[Text]: + return gca().pie_label( + container, + labels, + distance=distance, + textprops=textprops, + rotate=rotate, + alignment=alignment, + ) + + +# 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, baseline="zero", data=None, **kwargs): + return gca().stackplot( + x, + *args, + labels=labels, + colors=colors, + 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 - 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) +# 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) - 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) +# 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 colormap to 'autumn'. - 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("autumn") -# 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 +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def bone() -> None: + """ + Set the colormap to 'bone'. -# 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) + 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("bone") - 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) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def cool() -> None: + """ + Set the colormap to 'cool'. - 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("cool") -# 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 +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def copper() -> None: + """ + Set the colormap to 'copper'. -# 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() + 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("copper") - 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 +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def flag() -> None: + """ + Set the colormap to 'flag'. -# 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 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.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) +# 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.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) +# 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.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) +# 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.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) +# 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.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 +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def pink() -> None: + """ + Set the colormap to 'pink'. -# 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 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 -@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 +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def prism() -> None: + """ + Set the colormap to 'prism'. -# 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 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 -@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 +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def spring() -> None: + """ + Set the colormap to 'spring'. -# 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 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 -@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 +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def summer() -> None: + """ + Set the colormap to 'summer'. -# 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 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 -@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() +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def winter() -> None: + """ + Set the colormap to 'winter'. - 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() + 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") - 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() +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def magma() -> None: + """ + Set the colormap to 'magma'. - 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() + 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") - 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() +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def inferno() -> None: + """ + Set the colormap to 'inferno'. - 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() + 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") - 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() +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def plasma() -> None: + """ + Set the colormap to 'plasma'. - 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() + 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") - 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() +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def viridis() -> None: + """ + Set the colormap to 'viridis'. - 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() + 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") - 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() +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def nipy_spectral() -> None: + """ + Set the colormap to 'nipy_spectral'. -_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 218ee5355539..da1e85950933 100644 --- a/lib/matplotlib/quiver.py +++ b/lib/matplotlib/quiver.py @@ -14,346 +14,422 @@ 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 = r""" +Plot a 2D field of arrows. + +Call signature:: + + quiver([X, Y], U, V, [C], /, **kwargs) + +*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. + +**Arrow length** + +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. + +**Arrow shape** + +The arrow shape is determined by *width*, *headwidth*, *headlength* and +*headaxislength*. See the notes below. +**Arrow styling** -_quiver_doc = """ -Plot a 2-D field of arrows. +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. -call signatures:: - quiver(U, V, **kw) - quiver(U, V, C, **kw) - quiver(X, Y, U, V, **kw) - quiver(X, Y, U, V, C, **kw) +Parameters +---------- +X, Y : 1D or 2D array-like, optional + The x and y coordinates of the arrow locations. -Arguments: + If not given, they will be generated as a uniform integer meshgrid based + on the dimensions of *U* and *V*. - *X*, *Y*: - The x and y coordinates of the arrow locations (default is tail of - arrow; see *pivot* kwarg) + 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*. - *U*, *V*: - Give the x and y components of the arrow vectors +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*. - *C*: - An optional array used to map colors to the arrows + *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. -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`. +C : 1D or 2D array-like, optional + Numeric data that defines the arrow colors by colormapping via *norm* and + *cmap*. -*U*, *V*, *C* may be masked arrays, but masked *X*, *Y* are not -supported at present. + 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. -Keyword arguments: +angles : {'uv', 'xy'} or array-like, default: 'uv' + Method for determining the angle of the arrows. - *units*: [ 'width' | 'height' | 'dots' | 'inches' | 'x' | 'y' | 'xy' ] - Arrow units; the arrow dimensions *except for length* are in - multiples of this unit. + - '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' or 'height': the width or height of the axes + If *U* == *V* the orientation of the arrow on the plot is 45 degrees + counter-clockwise from the horizontal axis (positive to the right). - * 'dots' or 'inches': pixels or inches, based on the figure dpi + - '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. - * 'x', 'y', or 'xy': *X*, *Y*, or sqrt(X^2+Y^2) data units + - Arbitrary angles may be specified explicitly as an array of values + in degrees, counter-clockwise from the horizontal axis. - 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. + In this case *U*, *V* is only used to determine the length of the + arrows. + For example, ``angles=[30, 60, 90]`` will orient the arrows at 30, 60, and 90 + degrees respectively, regardless of the *U* and *V* components. - *angles*: [ 'uv' | 'xy' | array ] - With the default 'uv', the arrow axis aspect ratio is 1, so that - if *U*==*V* the orientation of the arrow on the plot is 45 degrees - CCW from the horizontal axis (positive to the right). - With 'xy', the arrow points from (x,y) to (x+u, y+v). - Use this for plotting a gradient field, for example. - Alternatively, arbitrary angles may be specified as an array - of values in degrees, CCW from the horizontal axis. Note: inverting a data axis will correspondingly invert the - arrows *only* with `angles='xy'`. + arrows only with ``angles='xy'``. - *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 +pivot : {'tail', 'middle', 'tip'}, default: 'tail' + The part of the arrow that is anchored to the *X*, *Y* grid. The arrow + rotates about this point. - *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. + .. admonition:: Discouraged - 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". + 'mid' is a synonym for 'middle', which is retained for backwards + compatibility. New code should use 'middle'. - *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. +scale : float, optional + Scales the length of the arrow inversely. - *headwidth*: scalar - Head width as multiple of shaft width, default is 3 + 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. - *headlength*: scalar - Head length as multiple of shaft width, default is 5 + 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. - *headaxislength*: scalar - Head length at shaft intersection, default is 4.5 + The arrow length unit is given by the *scale_units* parameter. - *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 +scale_units : {'width', 'height', 'dots', 'inches', 'x', 'y', 'xy'}, default: 'width' + The physical image unit, which is used for rendering the scaled arrow data U, V. - *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. + The rendered arrow length is given by: - *pivot*: [ 'tail' | 'mid' | 'middle' | 'tip' ] - The part of the arrow that is at the grid point; the arrow rotates - about this point, hence the name *pivot*. + - length in x direction = :math:`\frac{u}{\mathrm{scale}}\,\mathrm{scale\_unit}` + - length in y direction = :math:`\frac{v}{\mathrm{scale}}\,\mathrm{scale\_unit}` + For example, ``(u, v) = (0.5, 0)`` with ``scale=10, scale_units="width"`` results + in a horizontal arrow with a length of *0.5 / 10 * "width"*, i.e. 0.05 times the + Axes width. - *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. + Supported values are: -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. + - '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. -linewidths and edgecolors can be used to customize the arrow -outlines. Additional :class:`~matplotlib.collections.PolyCollection` -keyword arguments: + - 'dots': The arrow length of the arrows is in measured in display dots (pixels). -%(PolyCollection)s -""" % docstring.interpd.params + - '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. -_quiverkey_doc = """ -Add a key to a quiver plot. + - '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. -Call signature:: + - '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``. - quiverkey(Q, X, Y, U, label, **kw) + 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. -Arguments: +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. - *Q*: - The Quiver instance returned by a call to quiver. + Supported values are: - *X*, *Y*: - The location of the key; additional explanation follows. + - '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. - *U*: - The length of the key + The following table summarizes how these values affect the visible arrow + size under zooming and figure size changes: - *label*: - A string with the length and units of the key + ================= ================= ================== + units zoom figure size change + ================= ================= ================== + 'x', 'y', 'xy' arrow size scales — + 'width', 'height' — arrow size scales + 'dots', 'inches' — — + ================= ================= ================== -Keyword arguments: +width : float, optional + Shaft width in arrow units. All head parameters are relative to *width*. - *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. + 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. - *color*: - overrides face and edge colors from *Q*. +headwidth : float, default: 3 + Head width as multiple of shaft *width*. See the notes below. - *labelpos* = [ 'N' | 'S' | 'E' | 'W' ] - Position the label above, below, to the right, to the left of the - arrow, respectively. +headlength : float, default: 5 + Head length as multiple of shaft *width*. See the notes below. - *labelsep*: - Distance in inches between the arrow and the label. Default is - 0.1 +headaxislength : float, default: 4.5 + Head length at shaft intersection as multiple of shaft *width*. + See the notes below. - *labelcolor*: - defaults to default :class:`~matplotlib.text.Text` color. +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! - *fontproperties*: - A dictionary with keyword arguments accepted by the - :class:`~matplotlib.font_manager.FontProperties` initializer: - *family*, *style*, *variant*, *size*, *weight* +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. -Any additional keyword arguments are used to override vector -properties taken from *Q*. +color : :mpltype:`color` or list :mpltype:`color`, optional + Explicit color(s) for the arrows. If *C* has been set, *color* has no + effect. -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. -""" + 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 - 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) - - __init__.__doc__ = _quiverkey_doc + self.labelpos = labelpos + self._kw = kwargs # Remove when kw deprecation elapses. + self.vector = mcollections.PolyCollection( + [], **{**self.Q.polykw, **kwargs}) + self.text = mtext.Text( + text=label, + horizontalalignment=self.halign[self.labelpos], + verticalalignment=self.valign[self.labelpos], + fontproperties=fontproperties or {}) + if labelcolor is not None: + self.text.set_color(labelcolor) + self._dpi_at_last_init = None + self.zorder = zorder if zorder is not None else Q.zorder + 0.1 + + kw = _api.deprecated("3.11")( # Also remove self._kw when deprecation elapses. + property(lambda self: self._kw)) + fontproperties = _api.deprecated( + "3.11", alternative="quiverkey.text.get_fontproperties()")( + property(lambda self: self.text.get_fontproperties())) + labelcolor = _api.deprecated( + "3.11", alternative="quiverkey.text.get_color()")( + property(lambda self: self.text.get_color())) + verts = _api.deprecated( + "3.11", alternative="[p.vertices for p in quiverkey.vector.get_paths()]")( + property(lambda self: [p.vertices for p in self.vector.get_paths()])) + + @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: - 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) - self.vector = mcollections.PolyCollection( - self.verts, - offsets=[(self.X, self.Y)], - transOffset=self.get_transform(), - **kw) - 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 - - 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 - - @allow_rasterization + if False: # self._dpi_at_last_init == self.axes.get_figure().dpi + return + if self.Q._dpi_at_last_init != self.Q.axes.get_figure(root=True).dpi: + self.Q._init() + self._set_transform() + 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])) + verts = self.Q._make_verts([[0., 0.]], u, v, 'uv') + self.vector.set( + verts=verts, + offsets=[(self.X, self.Y)], + offset_transform=self.get_transform(), + transform=self.Q.get_transform(), + figure=self.get_figure(), + ) + if self.color is not None: + self.vector.set_color(self.color) + self._dpi_at_last_init = self.Q.axes.get_figure(root=True).dpi + + def _text_shift(self): + return { + "N": (0, +self.labelsep), + "S": (0, -self.labelsep), + "E": (+self.labelsep, 0), + "W": (-self.labelsep, 0), + }[self.labelpos] + + @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.getitem_checked({ + "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 @@ -361,45 +437,71 @@ def contains(self, mouseevent): 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. - The only API method is set_UVC(), which can be used - to change the size, orientation, and color of the - arrows; their locations are fixed when the class is - instantiated. Possibly this method will be useful - in animations. + Use set_UVC to change the size, orientation, and color of the + arrows; their locations can be set using set_offsets(). Much of the work in this class is done in the draw() method so that as much information as possible is available @@ -409,84 +511,49 @@ class Quiver(mcollections.PolyCollection): in the draw() method. """ - _PIVOT_VALS = ('tail', 'mid', 'middle', 'tip') + _PIVOT_VALS = ('tail', 'middle', 'tip') - @docstring.Substitution(_quiver_doc) - def __init__(self, ax, *args, **kw): + @_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') - - pivot = kw.pop('pivot', 'tail').lower() - # validate pivot - if pivot not in self._PIVOT_VALS: - raise ValueError( - 'pivot must be one of {keys}, you passed {inp}'.format( - keys=self._PIVOT_VALS, inp=pivot)) - # normalize to 'middle' - if pivot == 'mid': + 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 - - 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.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): """ @@ -495,45 +562,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() - verts = self._make_verts(self.U, self.V) + verts = self._make_verts(self.XY, self.U, self.V, self.angles) self.set_verts(verts, closed=False) - self._new_UV = False - mcollections.PolyCollection.draw(self, renderer) + 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() @@ -544,44 +618,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.getitem_checked({ + '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) @@ -590,32 +645,38 @@ 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: @@ -625,6 +686,7 @@ def _make_verts(self, U, V): # 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 @@ -639,19 +701,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 @@ -661,9 +719,9 @@ 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) @@ -684,25 +742,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) + 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 == 'tip': - X = X - X[:, 3, np.newaxis] # numpy bug? using -= does not - # work here unless we multiply - # by a float first, as with 'mid'. + # 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: @@ -712,155 +773,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) + - 'half' - half barbs (Default is 5) + - 'full' - full barbs (Default is 10) + - 'flag' - flags (default is 50) - - 'full' - full barbs (Default is 10) +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). - - 'flag' - flags (default is 50) + 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*. - *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 +Returns +------- +barbs : `~matplotlib.quiver.Barbs` -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:: +Other Parameters +---------------- +data : indexable object, optional + DATA_PARAMETER_PLACEHOLDER - : /\ \\ - : / \ \\ - : / \ \ \\ - : / \ \ \\ - : ------------------------------ +**kwargs + The barbs can further be customized using `.PolyCollection` keyword + arguments: -.. note the double \\ at the end of each line to make the figure -.. render correctly + %(PolyCollection:kwdoc)s +""" % _docstring.interpd.params -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. - -linewidths and edgecolors can be used to customize the barb. -Additional :class:`~matplotlib.collections.PolyCollection` keyword -arguments: - -%(PolyCollection)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 @@ -868,143 +928,151 @@ 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): + + @_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 + 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') + 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) + 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 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. - ''' - + """ + 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 @@ -1016,12 +1084,11 @@ def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length, # 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. @@ -1054,6 +1121,9 @@ def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length, 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 @@ -1063,7 +1133,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 @@ -1074,7 +1144,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 @@ -1089,7 +1159,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 @@ -1102,27 +1172,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 @@ -1130,23 +1212,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..02d622f6bb5c --- /dev/null +++ b/lib/matplotlib/quiver.pyi @@ -0,0 +1,189 @@ +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"] + 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 kw(self) -> dict[str, Any]: ... + @property + def fontproperties(self) -> dict[str, Any]: ... + @property + def labelcolor(self) -> ColorType | None: ... + @property + def verts(self) -> Sequence[ArrayLike]: ... + @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 b25788da001e..f88f07c0e82d 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -1,293 +1,415 @@ """ -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. New rcparams also need to be added to the RcKeyType enum +in :file:`lib/matplotlib/typing.py`. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six +import ast +from dataclasses import dataclass +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 +import re +from typing import Any +from collections.abc import Callable -#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 numpy as np -interactive_bk = ['GTK', 'GTKAgg', 'GTKCairo', 'MacOSX', - 'Qt4Agg', 'Qt5Agg', 'TkAgg', 'WX', 'WXAgg', 'CocoaAgg', - 'GTK3Cairo', 'GTK3Agg', 'WebAgg', 'nbAgg'] +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 +# Don't let the original cycler collide with our validating cycler +from cycler import Cycler, concat as cconcat, cycler as ccycler -non_interactive_bk = ['agg', 'cairo', 'emf', 'gdk', - 'pdf', 'pgf', 'ps', 'svg', 'template'] -all_backends = interactive_bk + non_interactive_bk - -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 __repr__(self): + return (f"{self.__class__.__name__}(" + f"key={self.key!r}, valid={[*self.valid.values()]}, " + f"ignorecase={self.ignorecase})") + + def __eq__(self, other): + if self is other: + return True + if not isinstance(other, ValidateInStrings): + return NotImplemented + return ( + self.key, + self.ignorecase, + self._deprecated_since, + tuple(sorted(self.valid.items())) + ) == ( + other.key, + other.ignorecase, + other._deprecated_since, + tuple(sorted(other.valid.items())) + ) + + def __hash__(self): + return hash(( + self.key, + self.ignorecase, + self._deprecated_since, + tuple(sorted(self.valid.items())) + )) + + +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): - 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) - - -def validate_bool_maybe_none(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 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) + raise ValueError(f'Cannot convert {b!r} to bool') -def validate_float(s): - """convert s to float or raise""" +def validate_axisbelow(s): try: - return float(s) + return validate_bool(s) except ValueError: - raise ValueError('Could not convert "%s" to float' % s) + 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_or_None(s): - """convert s to float or raise""" - if s is None: - return None +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 validate_int(s): - """convert s to int or raise""" + 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_intlist = _listify_validator(validate_int, n=2) +validate_float = _make_type_validator(float) +validate_float_or_None = _make_type_validator(float, allow_none=True) +validate_floatlist = _listify_validator( + validate_float) + + +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 + # 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: + if is_color_like(color): + return color - raise ValueError('%s does not look like a color arg%s' % (s, msg)) + raise ValueError(f'{s!r} does not look like a color arg') -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(',')] - else: - assert type(s) in [list, tuple] - return [validate_color(c) for c in s] +def _validate_color_or_None(s): + if s is None or cbook._str_equal(s, "None"): + return None + return validate_color(s) -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): @@ -295,565 +417,3013 @@ 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)) + 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.") -def validate_corner_mask(s): - if s == 'legacy': - return s - else: - return validate_bool(s) +def _validate_linestyle_or_None(s): + if s is None or cbook._str_equal(s, "None"): + return None -def validate_tkpythoninspect(s): - # Introduced 2010/07/05 - warnings.warn("tk.pythoninspect is obsolete, and has no effect") - return validate_bool(s) + return _validate_linestyle(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) +validate_fillstyle = ValidateInStrings( + 'markers.fillstyle', ['full', 'left', 'right', 'bottom', 'top', 'none']) -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']) +validate_fillstylelist = _listify_validator(validate_fillstyle) -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'") +def validate_markevery(s): + """ + Validate the markevery property of a Line2D object. -validate_pgf_texsystem = ValidateInStrings('pgf.texsystem', - ['xelatex', 'lualatex', 'pdflatex']) + 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_movie_writer = ValidateInStrings('animation.writer', - ['ffmpeg', 'ffmpeg_file', - 'avconv', 'avconv_file', - 'mencoder', 'mencoder_file', - 'imagemagick', 'imagemagick_file']) -validate_movie_frame_fmt = ValidateInStrings('animation.frame_format', - ['png', 'jpeg', 'tiff', 'raw', 'rgba']) +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)) + + +def _parse_cycler_string(s): + """ + Parse a string representation of a cycler into a Cycler object safely, + without using eval(). + + Accepts expressions like:: + + cycler('color', ['r', 'g', 'b']) + cycler('color', 'rgb') + cycler('linewidth', [1, 2, 3]) + cycler(c='rgb', lw=[1, 2, 3]) + cycler('c', 'rgb') * cycler('linestyle', ['-', '--']) + """ + try: + tree = ast.parse(s, mode='eval') + except SyntaxError as e: + raise ValueError(f"Could not parse {s!r}: {e}") from e + return _eval_cycler_expr(tree.body) + + +def _eval_cycler_expr(node): + """Recursively evaluate an AST node to build a Cycler object.""" + if isinstance(node, ast.BinOp): + left = _eval_cycler_expr(node.left) + right = _eval_cycler_expr(node.right) + if isinstance(node.op, ast.Add): + return left + right + if isinstance(node.op, ast.Mult): + return left * right + raise ValueError(f"Unsupported operator: {type(node.op).__name__}") + if isinstance(node, ast.Call): + if not (isinstance(node.func, ast.Name) + and node.func.id in ('cycler', 'concat')): + raise ValueError( + "only the 'cycler()' and 'concat()' functions are allowed") + func = cycler if node.func.id == 'cycler' else cconcat + args = [_eval_cycler_expr(a) for a in node.args] + kwargs = {kw.arg: _eval_cycler_expr(kw.value) for kw in node.keywords} + return func(*args, **kwargs) + if isinstance(node, ast.Subscript): + sl = node.slice + if not isinstance(sl, ast.Slice): + raise ValueError("only slicing is supported, not indexing") + s = slice( + ast.literal_eval(sl.lower) if sl.lower else None, + ast.literal_eval(sl.upper) if sl.upper else None, + ast.literal_eval(sl.step) if sl.step else None, + ) + value = _eval_cycler_expr(node.value) + return value[s] + # Allow literal values (int, strings, lists, tuples) as arguments + # to cycler() and concat(). + try: + return ast.literal_eval(node) + except (ValueError, TypeError): + raise ValueError( + f"Unsupported expression in cycler string: {ast.dump(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: - 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)) + 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): + try: + s = _parse_cycler_string(s) + except Exception as e: + raise ValueError(f"{s!r} is not a valid cycler construction: {e}" + ) from e + 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") + +class _ignorecase(list): + """A marker class indicating that a list-of-str is case-insensitive.""" -# 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], + +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', 'Felipa', '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], - # Specify whether vector graphics backends will combine all images on a - # set of axes into a single composite image - 'image.composite_image': [True, validate_bool], + "text.color": validate_color, + "text.usetex": validate_bool, + "text.latex.engine": ["latex", "latex+dvipng"], + "text.latex.preamble": validate_string, + "text.hinting": ["default", "no_autohint", "force_autohint", + "no_hinting", "auto", "native", "either", "none"], + "text.hinting_factor": validate_int_or_None, + "text.kerning_factor": validate_int_or_None, + "text.antialiased": validate_bool, + "text.parse_math": validate_bool, + "text.language": validate_string_or_None, + + "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", "normal"], + "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': ['dashed', - validate_negative_linestyle_legacy], - 'contour.corner_mask': [True, validate_corner_mask], - - # 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], + "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, + "errorbar.capthick": validate_float_or_None, + "errorbar.elinewidth": validate_float_or_None, + + # 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": validate_intlist, + # 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 is parsed safely via AST. + "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, + "axes3d.snap_rotation": 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': [None, validate_float_or_None], + "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, + # linewidth of legend frame + "legend.linewidth": 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, + + "grid.major.color": _validate_color_or_None, # grid color + "grid.major.linestyle": _validate_linestyle_or_None, # solid + "grid.major.linewidth": validate_float_or_None, # in points + "grid.major.alpha": validate_float_or_None, + + "grid.minor.color": _validate_color_or_None, # grid color + "grid.minor.linestyle": _validate_linestyle_or_None, # solid + "grid.minor.linewidth": validate_float_or_None, # in points + "grid.minor.alpha": validate_float_or_None, ## 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, - # Maintain shell focus for TkAgg - 'tk.window_focus': [False, validate_bool], - 'tk.pythoninspect': [False, validate_tkpythoninspect], # obsolete + "tk.window_focus": validate_bool, # Maintain shell focus for TkAgg # 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()} + + +@dataclass +class _Param: + name: str + default: Any + validator: Callable[[Any], Any] + description: str = None + + +@dataclass +class _Section: + title: str + description: str = None + + +@dataclass +class _Subsection: + title: str + description: str = None + + +# Definition of all rcParams. This is currently only used to generate the documentation. +# +# Actual runtime values do still come from the historic sources: +# - available parameters and defaults: lib/matplotlib/mpl-data/matplotlibrc +# - validators: _validators, see above +# +# The structure and format of this definition is not fixed and may change in the future. +# It's a work-in-progress state towards a consistent and more structured definition of +# rcParams that can be used both for documentation and runtime. The goal is to +# eventually eliminate the old sources of defaults and validators and have this be the +# single source of truth. +# +# In the transition phase, consistency is ensured via tests. +_DEFINITION = [ + _Section("Backends"), + _Param( + "webagg.port", + default=8988, + validator=validate_int, + description="The port to use for the web server in the WebAgg backend." + ), + _Param( + "webagg.address", + default="127.0.0.1", + validator=validate_string, + description="The address on which the WebAgg web server should be reachable." + ), + _Param( + "webagg.port_retries", + default=50, + validator=validate_int, + description="If webagg.port is unavailable, a number of other random ports " + "will be tried until one that is available is found." + ), + _Param( + "webagg.open_in_browser", + default=True, + validator=validate_bool, + description="When True, open the web browser to the plot that is shown" + ), + _Param( + "backend_fallback", + default=True, + validator=validate_bool, + description="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" + ), + _Param( + "interactive", + default=False, + validator=validate_bool + ), + _Param( + "figure.hooks", + default=[], + validator=validate_stringlist, + description="list of dotted.module.name:dotted.callable.name" + ), + _Param( + "toolbar", + default="toolbar2", + validator=_validate_toolbar, + description="{None, toolbar2, toolmanager}" + ), + _Param( + "timezone", + default="UTC", + validator=validate_string, + description="a pytz timezone string, e.g., US/Central or Europe/Paris" + ), + _Section( + "Lines", + description="Default properties for line objects, such as those returned by " + "plot()." + ), + _Param( + "lines.linewidth", + default=1.5, + validator=validate_float, + description="line width in points" + ), + _Param( + "lines.linestyle", + default="-", + validator=_validate_linestyle, + description="solid line" + ), + _Param( + "lines.color", + default="C0", + validator=validate_color, + description="has no affect on plot(); see axes.prop_cycle" + ), + _Param( + "lines.marker", + default="None", + validator=_validate_marker, + description="the default marker" + ), + _Param( + "lines.markerfacecolor", + default="auto", + validator=validate_color_or_auto, + description="the default marker face color" + ), + _Param( + "lines.markeredgecolor", + default="auto", + validator=validate_color_or_auto, + description="the default marker edge color" + ), + _Param( + "lines.markeredgewidth", + default=1.0, + validator=validate_float, + description="the line width around the marker symbol" + ), + _Param( + "lines.markersize", + default=6.0, + validator=validate_float, + description="marker size, in points" + ), + _Param( + "lines.dash_joinstyle", + default="round", + validator=JoinStyle, + description="{miter, round, bevel}" + ), + _Param( + "lines.dash_capstyle", + default="butt", + validator=CapStyle, + description="{butt, round, projecting}" + ), + _Param( + "lines.solid_joinstyle", + default="round", + validator=JoinStyle, + description="{miter, round, bevel}" + ), + _Param( + "lines.solid_capstyle", + default="projecting", + validator=CapStyle, + description="{butt, round, projecting}" + ), + _Param( + "lines.antialiased", + default=True, + validator=validate_bool, + description="render lines in antialiased (no jaggies)" + ), + _Param( + "lines.dashed_pattern", + default=[3.7, 1.6], + validator=validate_floatlist, + description="The dash pattern for linestyle 'dashed'" + ), + _Param( + "lines.dashdot_pattern", + default=[6.4, 1.6, 1.0, 1.6], + validator=validate_floatlist, + description="The dash pattern for linestyle 'dashdot'" + ), + _Param( + "lines.dotted_pattern", + default=[1.0, 1.65], + validator=validate_floatlist, + description="The dash pattern for linestyle 'dotted'" + ), + _Param( + "lines.scale_dashes", + default=True, + validator=validate_bool + ), + _Param( + "markers.fillstyle", + default="full", + validator=validate_fillstyle, + description="{full, left, right, bottom, top, none}" + ), + _Param( + "pcolor.shading", + default="auto", + validator=["auto", "flat", "nearest", "gouraud"] + ), + _Param( + "pcolormesh.snap", + default=True, + validator=validate_bool, + description="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." + ), + _Section("Patches"), + _Param( + "patch.linewidth", + default=1.0, + validator=validate_float, + description="edge width in points." + ), + _Param( + "patch.facecolor", + default="C0", + validator=validate_color + ), + _Param( + "patch.edgecolor", + default="black", + validator=validate_color, + description='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.' + ), + _Param( + "patch.force_edgecolor", + default=False, + validator=validate_bool, + description="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." + ), + _Param( + "patch.antialiased", + default=True, + validator=validate_bool, + description="render patches in antialiased (no jaggies)" + ), + _Section("Hatches"), + _Param("hatch.color", "edge", _validate_color_or_edge), + _Param("hatch.linewidth", 1.0, validate_float), + _Section("Boxplot"), + _Param("boxplot.notch", False, validate_bool), + _Param("boxplot.vertical", True, validate_bool), + _Param("boxplot.whiskers", 1.5, validate_whiskers), + _Param("boxplot.bootstrap", None, validate_int_or_None), + _Param("boxplot.patchartist", False, validate_bool), + _Param("boxplot.showmeans", False, validate_bool), + _Param("boxplot.showcaps", True, validate_bool), + _Param("boxplot.showbox", True, validate_bool), + _Param("boxplot.showfliers", True, validate_bool), + _Param("boxplot.meanline", False, validate_bool), + _Param("boxplot.flierprops.color", "black", validate_color), + _Param("boxplot.flierprops.marker", "o", _validate_marker), + _Param("boxplot.flierprops.markerfacecolor", "none", validate_color_or_auto), + _Param("boxplot.flierprops.markeredgecolor", "black", validate_color), + _Param("boxplot.flierprops.markeredgewidth", 1.0, validate_float), + _Param("boxplot.flierprops.markersize", 6.0, validate_float), + _Param("boxplot.flierprops.linestyle", "none", _validate_linestyle), + _Param("boxplot.flierprops.linewidth", 1.0, validate_float), + _Param("boxplot.boxprops.color", "black", validate_color), + _Param("boxplot.boxprops.linewidth", 1.0, validate_float), + _Param("boxplot.boxprops.linestyle", "-", _validate_linestyle), + _Param("boxplot.whiskerprops.color", "black", validate_color), + _Param("boxplot.whiskerprops.linewidth", 1.0, validate_float), + _Param("boxplot.whiskerprops.linestyle", "-", _validate_linestyle), + _Param("boxplot.capprops.color", "black", validate_color), + _Param("boxplot.capprops.linewidth", 1.0, validate_float), + _Param("boxplot.capprops.linestyle", "-", _validate_linestyle), + _Param("boxplot.medianprops.color", "C1", validate_color), + _Param("boxplot.medianprops.linewidth", 1.0, validate_float), + _Param("boxplot.medianprops.linestyle", "-", _validate_linestyle), + _Param("boxplot.meanprops.color", "C2", validate_color), + _Param("boxplot.meanprops.marker", "^", _validate_marker), + _Param("boxplot.meanprops.markerfacecolor", "C2", validate_color), + _Param("boxplot.meanprops.markeredgecolor", "C2", validate_color), + _Param("boxplot.meanprops.markersize", 6.0, validate_float), + _Param("boxplot.meanprops.linestyle", "--", _validate_linestyle), + _Param("boxplot.meanprops.linewidth", 1.0, validate_float), + _Section( + "Font", + description="The font properties used by `.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." + ), + _Param("font.family", ["sans-serif"], validate_stringlist), + _Param("font.style", "normal", validate_string), + _Param("font.variant", "normal", validate_string), + _Param("font.weight", "normal", validate_fontweight), + _Param("font.stretch", "normal", validate_fontstretch), + _Param("font.size", 10.0, validate_float), + _Param( + "font.serif", + default=[ + "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", + ], + validator=validate_stringlist + ), + _Param( + "font.sans-serif", + default=[ + "DejaVu Sans", "Bitstream Vera Sans", "Computer Modern Sans Serif", + "Lucida Grande", "Verdana", "Geneva", "Lucid", "Arial", "Helvetica", + "Avant Garde", "sans-serif", + ], + validator=validate_stringlist + ), + _Param( + "font.cursive", + default=[ + "Apple Chancery", "Textile", "Zapf Chancery", "Sand", "Script MT", "Felipa", + "Comic Neue", "Comic Sans MS", "cursive", + ], + validator=validate_stringlist + ), + _Param( + "font.fantasy", + default=["Chicago", "Charcoal", "Impact", "Western", "xkcd script", "fantasy"], + validator=validate_stringlist + ), + _Param( + "font.monospace", + default=[ + "DejaVu Sans Mono", "Bitstream Vera Sans Mono", + "Computer Modern Typewriter", "Andale Mono", "Nimbus Mono L", "Courier New", + "Courier", "Fixed", "Terminal", "monospace", + ], + validator=validate_stringlist + ), + _Param( + "font.enable_last_resort", + default=True, + validator=validate_bool, + description="If 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." + ), + _Section("Text properties"), + _Param( + "text.color", + default="black", + validator=validate_color + ), + _Param( + "text.language", + default=None, + validator=validate_string_or_None, + description="The language of the text in a format accepted by libraqm, namely " + "`a BCP47 language code " + "`_. If " + "None, then no particular language will be implied, and default " + "font settings will be used." + ), + _Param( + "text.hinting", + default="default", + validator=[ + "default", "no_autohint", "force_autohint", "no_hinting", "auto", "native", + "either", "none", + ], + description="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.)" + ), + _Param( + "text.hinting_factor", + default=None, + validator=validate_int_or_None, + description="[DEPRECATED] This setting has no effect." + ), + _Param( + "text.kerning_factor", + default=None, + validator=validate_int_or_None, + description="[DEPRECATED] 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." + ), + _Param( + "text.antialiased", + default=True, + validator=validate_bool, + description="If True (default), the text will be antialiased. This only " + "affects raster outputs." + ), + _Param( + "text.parse_math", + default=True, + validator=validate_bool, + description="Use mathtext if there is an even number of unescaped dollar signs." + + ), + _Section("Mathtext and LaTeX"), + _Param( + "text.usetex", + default=False, + validator=validate_bool, + description="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" + ), + _Param( + "text.latex.engine", + default="latex", + validator=["latex", "latex+dvipng"], + description=( + "The TeX engine/format to use. The following values are supported:\n" + "- 'latex': The classic TeX engine (the current default). All backends " + "render TeX's output by parsing the DVI output into glyphs and boxes and " + "emitting those one by one.\n" + "- 'latex+dvipng': The same as 'latex', with the exception that Agg-based " + "backends rely on dvipng to rasterize TeX's output. This value was the " + "default up to Matplotlib 3.10." + ) + ), + _Param( + "text.latex.preamble", + default="", + validator=validate_string, + description='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.' + ), + _Param( + "mathtext.fontset", + default="dejavusans", + validator=["dejavusans", "dejavuserif", "cm", "stix", "stixsans", "custom"], + description="Should be 'dejavusans' (default), 'dejavuserif', " + "'cm' (Computer Modern), 'stix', 'stixsans' or 'custom'" + ), + _Param("mathtext.bf", "sans:bold", validate_font_properties), + _Param("mathtext.bfit", "sans:italic:bold", validate_font_properties), + _Param("mathtext.cal", "cursive", validate_font_properties), + _Param("mathtext.it", "sans:italic", validate_font_properties), + _Param("mathtext.rm", "sans", validate_font_properties), + _Param("mathtext.sf", "sans", validate_font_properties), + _Param("mathtext.tt", "monospace", validate_font_properties), + _Param( + "mathtext.fallback", + default="cm", + validator=_validate_mathtext_fallback, + description="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." + ), + _Param("mathtext.default", "normal", + ["rm", "cal", "bfit", "it", "tt", "sf", "bf", "default", "bb", "frak", "scr", + "regular", "normal"], + description='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.', + ), + _Section("Axes"), + _Param( + "axes.facecolor", + default="white", + validator=validate_color, + description="axes background color" + ), + _Param( + "axes.edgecolor", + default="black", + validator=validate_color, + description="axes edge color" + ), + _Param( + "axes.linewidth", + default=0.8, + validator=validate_float, + description="edge line width" + ), + _Param( + "axes.grid", + default=False, + validator=validate_bool, + description="display grid or not" + ), + _Param( + "axes.grid.axis", + default="both", + validator=["x", "y", "both"], + description="which axis the grid should apply to" + ), + _Param( + "axes.grid.which", + default="major", + validator=["minor", "both", "major"], + description="grid lines at {major, minor, both} ticks" + ), + _Param( + "axes.titlelocation", + default="center", + validator=["left", "center", "right"], + description="alignment of the title: {left, right, center}" + ), + _Param( + "axes.titlesize", + default="large", + validator=validate_fontsize, + description="font size of the axes title" + ), + _Param( + "axes.titleweight", + default="normal", + validator=validate_fontweight, + description="font weight of title" + ), + _Param( + "axes.titlecolor", + default="auto", + validator=validate_color_or_auto, + description="color of the axes title, auto falls back to text.color as default " + "value" + ), + _Param( + "axes.titley", + default=None, + validator=validate_float_or_None, + description="position title (axes relative units). None implies auto" + ), + _Param( + "axes.titlepad", + default=6.0, + validator=validate_float, + description="pad between axes and title in points" + ), + _Param( + "axes.labelsize", + default="medium", + validator=validate_fontsize, + description="font size of the x and y labels" + ), + _Param( + "axes.labelpad", + default=4.0, + validator=validate_float, + description="space between label and axis" + ), + _Param( + "axes.labelweight", + default="normal", + validator=validate_fontweight, + description="weight of the x and y labels" + ), + _Param( + "axes.labelcolor", + default="black", + validator=validate_color + ), + _Param( + "axes.axisbelow", + default="line", + validator=validate_axisbelow, + description="draw axis gridlines and ticks: " + "- below patches (True) " + "- above patches but below lines ('line') " + "- above all (False)" + ), + _Param( + "axes.formatter.limits", + default=[-5, 6], + validator=validate_intlist, + description="use scientific notation if log10 of the axis range is smaller " + "than the first or larger than the second" + ), + _Param( + "axes.formatter.use_locale", + default=False, + validator=validate_bool, + description="When True, format tick labels according to the user's locale. " + "For example, use ',' as a decimal separator in the fr_FR locale." + ), + _Param( + "axes.formatter.use_mathtext", + default=False, + validator=validate_bool, + description="When True, use mathtext for scientific notation." + ), + _Param( + "axes.formatter.min_exponent", + default=0, + validator=validate_int, + description="minimum exponent to format in scientific notation" + ), + _Param( + "axes.formatter.useoffset", + default=True, + validator=validate_bool, + description="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." + ), + _Param( + "axes.formatter.offset_threshold", + default=4, + validator=validate_int, + description="When useoffset is True, the offset will be used when it can " + "remove at least this number of significant digits from tick " + "labels." + ), + _Param( + "axes.spines.left", + default=True, + validator=validate_bool, + description="display axis spines" + ), + _Param("axes.spines.bottom", True, validate_bool), + _Param("axes.spines.top", True, validate_bool), + _Param( + "axes.spines.right", + default=True, + validator=validate_bool + ), + _Param( + "axes.unicode_minus", + default=True, + validator=validate_bool, + description="use Unicode for the minus symbol rather than hyphen. See " + "https://en.wikipedia.org/wiki/Plus_and_minus_signs#Character_codes" + + ), + _Param("axes.prop_cycle", + default=cycler( + "color", + [(0.12156862745098039, 0.4666666666666667, 0.7058823529411765), + (1.0, 0.4980392156862745, 0.054901960784313725), + (0.17254901960784313, 0.6274509803921569, 0.17254901960784313), + (0.8392156862745098, 0.15294117647058825, 0.1568627450980392), + (0.5803921568627451, 0.403921568627451, 0.7411764705882353), + (0.5490196078431373, 0.33725490196078434, 0.29411764705882354), + (0.8901960784313725, 0.4666666666666667, 0.7607843137254902), + (0.4980392156862745, 0.4980392156862745, 0.4980392156862745), + (0.7372549019607844, 0.7411764705882353, 0.13333333333333333), + (0.09019607843137255, 0.7450980392156863, 0.8117647058823529), + ], + ), + validator=validate_cycler + ), + _Param( + "axes.xmargin", + default=0.05, + validator=_validate_greaterthan_minushalf, + description="x margin. See `~.axes.Axes.margins`" + ), + _Param( + "axes.ymargin", + default=0.05, + validator=_validate_greaterthan_minushalf, + description="y margin. See `~.axes.Axes.margins`" + ), + _Param( + "axes.zmargin", + default=0.05, + validator=_validate_greaterthan_minushalf, + description="z margin. See `~.axes.Axes.margins`" + ), + _Param( + "axes.autolimit_mode", + default="data", + validator=["data", "round_numbers"], + description='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.', + ), + _Subsection("Polar Axes"), + _Param( + "polaraxes.grid", + default=True, + validator=validate_bool, + description="display grid on polar axes" + ), + _Subsection("3D Axes"), + _Param( + "axes3d.grid", + default=True, + validator=validate_bool, description="display grid on 3D axes" + ), + _Param( + "axes3d.automargin", + default=False, + validator=validate_bool, + description="automatically add margin when manually setting 3D axis limits" + ), + _Param( + "axes3d.xaxis.panecolor", + default=(0.95, 0.95, 0.95, 0.5), + validator=validate_color, + description="background pane on 3D axes" + ), + _Param( + "axes3d.yaxis.panecolor", + default=(0.9, 0.9, 0.9, 0.5), + validator=validate_color, + description="background pane on 3D axes" + ), + _Param( + "axes3d.zaxis.panecolor", + default=(0.925, 0.925, 0.925, 0.5), + validator=validate_color, + description="background pane on 3D axes" + ), + _Param( + "axes3d.depthshade", + default=True, + validator=validate_bool, + description="depth shade for 3D scatter plots" + ), + _Param( + "axes3d.depthshade_minalpha", + default=0.3, + validator=validate_float, + description="minimum alpha value for depth shading" + ), + _Param( + "axes3d.mouserotationstyle", + default="arcball", + validator=["azel", "trackball", "sphere", "arcball"], + description="{azel, trackball, sphere, arcball} See also " + "https://matplotlib.org/stable/api/toolkits/mplot3d/view_angles.html#rotation-with-mouse"), # noqa + _Param( + "axes3d.trackballsize", + default=0.667, + validator=validate_float, + description="trackball diameter, in units of the Axes bbox" + ), + _Param( + "axes3d.trackballborder", + default=0.2, + validator=validate_float, + description="trackball border width, in units of the Axes bbox (only for " + "'sphere' and 'arcball' style)" + ), + _Section("Axis"), + _Param( + "axes3d.snap_rotation", + default=5.0, + validator=validate_float, + description="Snap angle (in degrees) for 3D rotation when holding Control." + ), + _Param( + "xaxis.labellocation", + default="center", + validator=["left", "center", "right"], + description="alignment of the xaxis label: {left, right, center}" + ), + _Param( + "yaxis.labellocation", + default="center", + validator=["bottom", "center", "top"], + description="alignment of the yaxis label: {bottom, top, center}" + ), + _Section( + "Dates", + description="Default properties for date tick labels. These are used by the " + "`.AutoDateFormatter` when the appropriate time unit is detected." + "See " + "https://matplotlib.org/stable/api/dates_api.html#date-formatters " + "for more information." + ), + _Param("date.autoformatter.year", "%Y", validate_string), + _Param("date.autoformatter.month", "%Y-%m", validate_string), + _Param("date.autoformatter.day", "%Y-%m-%d", validate_string), + _Param("date.autoformatter.hour", "%m-%d %H", validate_string), + _Param("date.autoformatter.minute", "%d %H:%M", validate_string), + _Param("date.autoformatter.second", "%H:%M:%S", validate_string), + _Param("date.autoformatter.microsecond", "%M:%S.%f", validate_string), + _Param( + "date.epoch", + default="1970-01-01T00:00:00", + validator=_validate_date, + description="The reference date for Matplotlib's internal date representation. " + "See https://matplotlib.org/stable/gallery/ticks/date_precision_and_epochs.html"), #noqa + _Param( + "date.converter", + default="auto", + validator=["auto", "concise"], + description="'auto', 'concise'" + ), + _Param( + "date.interval_multiples", + default=True, + validator=validate_bool, + description="For auto converter whether to use interval_multiples" + ), + _Section("Ticks"), + _Param( + "xtick.top", + default=False, + validator=validate_bool, + description="draw ticks on the top side" + ), + _Param( + "xtick.bottom", + default=True, + validator=validate_bool, + description="draw ticks on the bottom side" + ), + _Param( + "xtick.labeltop", + default=False, + validator=validate_bool, + description="draw label on the top" + ), + _Param( + "xtick.labelbottom", + default=True, + validator=validate_bool, + description="draw label on the bottom" + ), + _Param( + "xtick.major.size", + default=3.5, + validator=validate_float, + description="major tick size in points" + ), + _Param( + "xtick.minor.size", + default=2.0, + validator=validate_float, + description="minor tick size in points" + ), + _Param( + "xtick.major.width", + default=0.8, + validator=validate_float, + description="major tick width in points" + ), + _Param( + "xtick.minor.width", + default=0.6, + validator=validate_float, + description="minor tick width in points" + ), + _Param( + "xtick.major.pad", + default=3.5, + validator=validate_float, + description="distance to major tick label in points" + ), + _Param( + "xtick.minor.pad", + default=3.4, + validator=validate_float, + description="distance to the minor tick label in points" + ), + _Param( + "xtick.color", + default="black", + validator=validate_color, + description="color of the ticks" + ), + _Param( + "xtick.labelcolor", + default="inherit", + validator=validate_color_or_inherit, + description="color of the tick labels or inherit from xtick.color" + ), + _Param( + "xtick.labelsize", + default="medium", + validator=validate_fontsize, + description="font size of the tick labels" + ), + _Param( + "xtick.direction", + default="out", + validator=["out", "in", "inout"], + description="direction: {in, out, inout}" + ), + _Param( + "xtick.minor.visible", + default=False, + validator=validate_bool, + description="visibility of minor ticks on x-axis" + ), + _Param( + "xtick.major.top", + default=True, + validator=validate_bool, + description="draw x axis top major ticks" + ), + _Param( + "xtick.major.bottom", + default=True, + validator=validate_bool, + description="draw x axis bottom major ticks" + ), + _Param( + "xtick.minor.top", + default=True, + validator=validate_bool, + description="draw x axis top minor ticks" + ), + _Param( + "xtick.minor.bottom", + default=True, + validator=validate_bool, + description="draw x axis bottom minor ticks" + ), + _Param( + "xtick.minor.ndivs", + default="auto", + validator=_validate_minor_tick_ndivs, + description="number of minor ticks between the major ticks on x-axis" + ), + _Param( + "xtick.alignment", + default="center", + validator=["center", "right", "left"], + description="alignment of xticks" + ), + _Param( + "ytick.left", + default=True, + validator=validate_bool, + description="draw ticks on the left side" + ), + _Param( + "ytick.right", + default=False, + validator=validate_bool, + description="draw ticks on the right side" + ), + _Param( + "ytick.labelleft", + default=True, + validator=validate_bool, + description="draw tick labels on the left side" + ), + _Param( + "ytick.labelright", + default=False, + validator=validate_bool, + description="draw tick labels on the right side" + ), + _Param( + "ytick.major.size", + default=3.5, + validator=validate_float, + description="major tick size in points" + ), + _Param( + "ytick.minor.size", + default=2.0, + validator=validate_float, + description="minor tick size in points" + ), + _Param( + "ytick.major.width", + default=0.8, + validator=validate_float, + description="major tick width in points" + ), + _Param( + "ytick.minor.width", + default=0.6, + validator=validate_float, + description="minor tick width in points" + ), + _Param( + "ytick.major.pad", + default=3.5, + validator=validate_float, + description="distance to major tick label in points" + ), + _Param( + "ytick.minor.pad", + default=3.4, + validator=validate_float, + description="distance to the minor tick label in points" + ), + _Param( + "ytick.color", + default="black", + validator=validate_color, + description="color of the ticks" + ), + _Param( + "ytick.labelcolor", + default="inherit", + validator=validate_color_or_inherit, + description="color of the tick labels or inherit from ytick.color" + ), + _Param( + "ytick.labelsize", + default="medium", + validator=validate_fontsize, + description="font size of the tick labels" + ), + _Param( + "ytick.direction", + default="out", + validator=["out", "in", "inout"], + description="direction: {in, out, inout}" + ), + _Param( + "ytick.minor.visible", + default=False, + validator=validate_bool, + description="visibility of minor ticks on y-axis" + ), + _Param( + "ytick.major.left", + default=True, + validator=validate_bool, + description="draw y axis left major ticks" + ), + _Param( + "ytick.major.right", + default=True, + validator=validate_bool, + description="draw y axis right major ticks" + ), + _Param( + "ytick.minor.left", + default=True, + validator=validate_bool, + description="draw y axis left minor ticks" + ), + _Param( + "ytick.minor.right", + default=True, + validator=validate_bool, + description="draw y axis right minor ticks" + ), + _Param( + "ytick.minor.ndivs", + default="auto", + validator=_validate_minor_tick_ndivs, + description="number of minor ticks between the major ticks on y-axis" + ), + _Param("ytick.alignment", "center_baseline", + ["center", "top", "bottom", "baseline", "center_baseline"], + description="alignment of yticks" + ), + _Section("Grid"), + _Param( + "grid.color", + default="#b0b0b0", + validator=validate_color, + description='b0b0b0" # grid color' + ), + _Param( + "grid.linestyle", + default="-", + validator=_validate_linestyle, + description="solid" + ), + _Param( + "grid.linewidth", + default=0.8, + validator=validate_float, + description="in points" + ), + _Param( + "grid.alpha", + default=1.0, + validator=validate_float, + description="transparency, between 0.0 and 1.0" + ), + _Param( + "grid.major.color", + default=None, + validator=_validate_color_or_None, + description="If None defaults to grid.color" + ), + _Param( + "grid.major.linestyle", + default=None, + validator=_validate_linestyle_or_None, + description="If None defaults to grid.linestyle" + ), + _Param( + "grid.major.linewidth", + default=None, + validator=validate_float_or_None, + description="If None defaults to grid.linewidth" + ), + _Param( + "grid.major.alpha", + default=None, + validator=validate_float_or_None, + description="If None defaults to grid.alpha" + ), + _Param( + "grid.minor.color", + default=None, + validator=_validate_color_or_None, + description="If None defaults to grid.color" + ), + _Param( + "grid.minor.linestyle", + default=None, + validator=_validate_linestyle_or_None, + description="If None defaults to grid.linestyle" + ), + _Param( + "grid.minor.linewidth", + default=None, + validator=validate_float_or_None, + description="If None defaults to grid.linewidth" + ), + _Param( + "grid.minor.alpha", + default=None, + validator=validate_float_or_None, + description="If None defaults to grid.alpha" + ), + _Section("Legend"), + _Param( + "legend.loc", + default="best", + validator=_validate_legend_loc + ), + _Param( + "legend.frameon", + default=True, + validator=validate_bool, + description="if True, draw the legend on a background patch" + ), + _Param( + "legend.framealpha", + default=0.8, + validator=validate_float_or_None, + description="legend patch transparency" + ), + _Param( + "legend.facecolor", + default="inherit", + validator=validate_color_or_inherit, + description="inherit from axes.facecolor; or color spec" + ), + _Param( + "legend.edgecolor", + default="0.8", + validator=validate_color_or_inherit, + description="background patch boundary color" + ), + _Param( + "legend.linewidth", + default=None, + validator=validate_float_or_None, + description="line width of the legend frame, None means inherit from " + "patch.linewidth" + ), + _Param( + "legend.fancybox", + default=True, + validator=validate_bool, + description="if True, use a rounded box for the legend background, else a " + "rectangle" + ), + _Param( + "legend.shadow", + default=False, + validator=validate_bool, + description="if True, give background a shadow effect" + ), + _Param( + "legend.numpoints", + default=1, + validator=validate_int, + description="the number of marker points in the legend line" + ), + _Param( + "legend.scatterpoints", + default=1, + validator=validate_int, + description="number of scatter points" + ), + _Param( + "legend.markerscale", + default=1.0, + validator=validate_float, + description="the relative size of legend markers vs. original" + ), + _Param( + "legend.fontsize", + default="medium", + validator=validate_fontsize + ), + _Param( + "legend.labelcolor", + default="None", + validator=_validate_color_or_linecolor + ), + _Param( + "legend.title_fontsize", + default=None, + validator=validate_fontsize_None, + description="None sets to the same as the default axes." + ), + _Param( + "legend.borderpad", + default=0.4, + validator=validate_float, + description="border whitespace" + ), + _Param( + "legend.labelspacing", + default=0.5, + validator=validate_float, + description="the vertical space between the legend entries" + ), + _Param( + "legend.handlelength", + default=2.0, + validator=validate_float, + description="the length of the legend lines" + ), + _Param( + "legend.handleheight", + default=0.7, + validator=validate_float, + description="the height of the legend handle" + ), + _Param( + "legend.handletextpad", + default=0.8, + validator=validate_float, + description="the space between the legend line and legend text" + ), + _Param( + "legend.borderaxespad", + default=0.5, + validator=validate_float, + description="the border between the axes and legend edge" + ), + _Param( + "legend.columnspacing", + default=2.0, + validator=validate_float, description="column separation" + ), + _Section("Figure"), + _Param( + "figure.titlesize", + default="large", + validator=validate_fontsize, + description="size of the figure title (``Figure.suptitle()``)" + ), + _Param( + "figure.titleweight", + default="normal", + validator=validate_fontweight, + description="weight of the figure title" + ), + _Param( + "figure.labelsize", + default="large", + validator=validate_fontsize, + description="size of the figure label (``Figure.sup[x|y]label()``)" + ), + _Param( + "figure.labelweight", + default="normal", + validator=validate_fontweight, + description="weight of the figure label" + ), + _Param( + "figure.figsize", + default=[6.4, 4.8], + validator=_listify_validator(validate_float, n=2), + description="figure size in inches" + ), + _Param( + "figure.dpi", + default=100.0, + validator=validate_float, description="figure dots per inch" + ), + _Param( + "figure.facecolor", + default="white", + validator=validate_color, description="figure face color" + ), + _Param( + "figure.edgecolor", + default="white", + validator=validate_color, description="figure edge color" + ), + _Param( + "figure.frameon", + default=True, + validator=validate_bool, description="enable figure frame" + ), + _Param( + "figure.max_open_warning", + default=20, + validator=validate_int, + description="The maximum number of figures to open through the pyplot " + "interface before emitting a warning. If less than one this " + "feature is disabled." + ), + _Param( + "figure.raise_window", + default=True, + validator=validate_bool, + description="Raise the GUI window to front when show() is called. If set to " + "False, we currently do not take any further actions and whether " + "the window appears on the front may depend on the GUI framework " + "and window manager." + ), + _Param( + "figure.subplot.left", + default=0.125, + validator=validate_float, + description="the left side of the subplots of the figure" + ), + _Param( + "figure.subplot.right", + default=0.9, + validator=validate_float, + description="the right side of the subplots of the figure" + ), + _Param( + "figure.subplot.bottom", + default=0.11, + validator=validate_float, + description="the bottom of the subplots of the figure" + ), + _Param( + "figure.subplot.top", + default=0.88, + validator=validate_float, + description="the top of the subplots of the figure" + ), + _Param( + "figure.subplot.wspace", + default=0.2, + validator=validate_float, + description="the amount of width reserved for space between subplots, " + "expressed as a fraction of the average axis width" + ), + _Param( + "figure.subplot.hspace", + default=0.2, + validator=validate_float, + description="the amount of height reserved for space between subplots, " + "expressed as a fraction of the average axis height" + ), + _Param( + "figure.autolayout", + default=False, + validator=validate_bool, + description="When True, automatically adjust subplot parameters to make the " + "plot fit the figure using `~.Figure.tight_layout`" + ), + _Param( + "figure.constrained_layout.use", + default=False, + validator=validate_bool, + description="When True, automatically make plot elements fit on the figure. " + '(Not compatible with "figure.autolayout", above).' + ), + _Param( + "figure.constrained_layout.h_pad", + default=0.04167, + validator=validate_float, + description="Padding (in inches) around axes; defaults to 3/72 inches, " + "i.e. 3 points" + ), + _Param( + "figure.constrained_layout.w_pad", + default=0.04167, + validator=validate_float, + description="Padding (in inches) around axes; defaults to 3/72 inches, " + "i.e. 3 points" + ), + _Param( + "figure.constrained_layout.hspace", + default=0.02, + validator=validate_float, + description="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." + ), + _Param( + "figure.constrained_layout.wspace", + default=0.02, + validator=validate_float, + description="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." + ), + _Section("Images"), + _Param( + "image.aspect", + default="equal", + validator=validate_aspect, + description="{equal, auto} or a number" + ), + _Param( + "image.interpolation", + default="auto", + validator=validate_string, + description="see help(imshow) for options" + ), + _Param( + "image.interpolation_stage", + default="auto", + validator=["auto", "data", "rgba"], + description="see help(imshow) for options" + ), + _Param( + "image.cmap", + default="viridis", + validator=_validate_cmap, + description="A colormap name (plasma, magma, etc.)" + ), + _Param( + "image.lut", + default=256, + validator=validate_int, + description="the size of the colormap lookup table" + ), + _Param( + "image.origin", + default="upper", + validator=["upper", "lower"], description="{lower, upper}" + ), + _Param( + "image.resample", + default=True, + validator=validate_bool + ), + _Param( + "image.composite_image", + default=True, + validator=validate_bool, + description="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." + ), + _Section("Contour plots"), + _Param( + "contour.negative_linestyle", + default="dashed", + validator=_validate_linestyle, + description="string or on-off ink sequence" + ), + _Param( + "contour.corner_mask", + default=True, + validator=validate_bool, description="{True, False}" + ), + _Param( + "contour.linewidth", + default=None, + validator=validate_float_or_None, + description="{float, None} Size of the contour line widths. If set to None, it " + 'falls back to "line.linewidth".' + ), + _Param( + "contour.algorithm", + default="mpl2014", + validator=["mpl2005", "mpl2014", "serial", "threaded"], + description="{mpl2005, mpl2014, serial, threaded}" + ), + _Section("Errorbar plots"), + _Param( + "errorbar.capsize", + default=0.0, + validator=validate_float, + description="length of end cap on error bars in pixels" + ), + _Param( + "errorbar.capthick", + default=None, + validator=validate_float_or_None, + description="thickness of end cap on error bars in points."), + _Param( + "errorbar.elinewidth", + default=None, + validator=validate_float_or_None, + description="line width of the error bar lines in points." + ), + _Section("Histogram plots"), + _Param( + "hist.bins", + default=10, + validator=validate_hist_bins, + description="The default number of histogram bins or 'auto'." + ), + _Section("Scatter plots"), + _Param( + "scatter.marker", + default="o", + validator=_validate_marker, + description="The default marker type for scatter plots." + ), + _Param( + "scatter.edgecolors", + default="face", + validator=validate_string, + description="The default edge colors for scatter plots." + ), + _Section("AGG rendering"), + _Param( + "agg.path.chunksize", + default=0, + validator=validate_int, + description="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." + ), + _Section("Paths"), + _Param( + "path.simplify", + default=True, + validator=validate_bool, + description='When True, simplify paths by removing "invisible" points to ' + 'reduce file size and increase rendering speed', + ), + _Param( + "path.simplify_threshold", + default=0.111111111111, + validator=_validate_greaterequal0_lessequal1, + description="The threshold of similarity below which vertices will be removed " + "in the simplification process." + ), + _Param( + "path.snap", + default=True, + validator=validate_bool, + description="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." + ), + _Param( + "path.sketch", + default=None, + validator=validate_sketch, + description="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." + ), + _Param( + "path.effects", + default=[], + validator=validate_anylist + ), + _Section("Saving figures"), + _Param( + "savefig.dpi", + default="figure", + validator=validate_dpi, + description="figure dots per inch or 'figure'" + ), + _Param( + "savefig.facecolor", + default="auto", + validator=validate_color_or_auto, + description="figure face color when saving" + ), + _Param( + "savefig.edgecolor", + default="auto", + validator=validate_color_or_auto, + description="figure edge color when saving" + ), + _Param( + "savefig.format", + default="png", + validator=validate_string, description="{png, ps, pdf, svg}" + ), + _Param( + "savefig.bbox", + default=None, + validator=validate_bbox, + description="{tight, standard} 'tight' is incompatible with generating frames " + "for animation" + ), + _Param( + "savefig.pad_inches", + default=0.1, + validator=validate_float, + description="padding to be used, when bbox is set to 'tight'" + ), + _Param( + "savefig.directory", + default="~", + validator=_validate_pathlike, + description="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" + ), + _Param( + "savefig.transparent", + default=False, + validator=validate_bool, + description="whether figures are saved with a transparent background by default" + + ), + _Param( + "savefig.orientation", + default="portrait", + validator=["landscape", "portrait"], + description="orientation of saved figure, for PostScript output only" + ), + _Subsection("Mac OSX backend parameters"), + _Param( + "macosx.window_mode", + default="system", + validator=["system", "tab", "window"], + description="How to open new figures (system, tab, window) system uses " + "the MacOS system preferences" + ), + _Subsection("Tk backend parameters"), + _Param( + "tk.window_focus", + default=False, + validator=validate_bool, + description="Maintain shell focus for TkAgg" + ), + _Subsection("PS backend parameters"), + _Param( + "ps.papersize", + default="letter", + validator=_ignorecase( + ["figure", "letter", "legal", "ledger", + *[f"{ab}{i}" for ab in "ab" for i in range(11)], + ], + ), + description="{figure, letter, legal, ledger, A0-A10, B0-B10}" + ), + _Param( + "ps.useafm", + default=False, + validator=validate_bool, + description="use AFM fonts, results in small files" + ), + _Param( + "ps.usedistiller", + default=None, + validator=validate_ps_distiller, + description="{ghostscript, xpdf, None} Experimental: may produce smaller " + "files. xpdf intended for production of publication quality files, " + "but requires ghostscript, xpdf and ps2eps" + ), + _Param( + "ps.distiller.res", + default=6000, + validator=validate_int, description="dpi" + ), + _Param( + "ps.fonttype", + default=3, + validator=validate_fonttype, + description="Output Type 3 (Type3) or Type 42 (TrueType)" + ), + _Subsection("PDF backend parameters"), + _Param( + "pdf.compression", + default=6, + validator=validate_int, + description="integer from 0 to 9 0 disables compression (good for debugging)" + ), + _Param( + "pdf.fonttype", + default=3, + validator=validate_fonttype, + description="Output Type 3 (Type3) or Type 42 (TrueType)" + ), + _Param( + "pdf.use14corefonts", + default=False, + validator=validate_bool + ), + _Param( + "pdf.inheritcolor", + default=False, + validator=validate_bool + ), + _Subsection("SVG backend parameters"), + _Param( + "svg.image_inline", + default=True, + validator=validate_bool, + description="Write raster image data directly into the SVG file" + ), + _Param( + "svg.fonttype", + default="path", + validator=["none", "path"], + description="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." + ), + _Param( + "svg.hashsalt", + default=None, + validator=validate_string_or_None, + description="If not None, use this string as hash salt instead of uuid4" + ), + _Param( + "svg.id", + default=None, + validator=validate_string_or_None, + description="If not None, use this string as the value for the `id` attribute " + "in the top tag" + ), + _Subsection("PGF parameters"), + _Param( + "pgf.rcfonts", + default=True, + validator=validate_bool + ), + _Param( + "pgf.preamble", + default="", + validator=validate_string, + description="See text.latex.preamble for documentation" + ), + _Param( + "pgf.texsystem", + default="xelatex", + validator=["xelatex", "lualatex", "pdflatex"] + ), + _Subsection("Docstring parameters"), + _Param( + "docstring.hardcopy", + default=False, + validator=validate_bool, + description="set this when you want to generate hardcopy docstring" + ), + _Section( + "Interactive keymaps", + description="Default key mappings for interactive navigation. See " + ":ref:`key-event-handling`." + ), + _Param( + "keymap.fullscreen", + default=["f", "ctrl+f"], + validator=validate_stringlist, + description="toggling" + ), + _Param( + "keymap.home", + default=["h", "r", "home"], + validator=validate_stringlist, + description="home or reset mnemonic" + ), + _Param( + "keymap.back", + default=["left", "c", "backspace", "MouseButton.BACK"], + validator=validate_stringlist, description="forward / backward keys" + ), + _Param( + "keymap.forward", + default=["right", "v", "MouseButton.FORWARD"], + validator=validate_stringlist, + description="for quick navigation" + ), + _Param( + "keymap.pan", + default=["p"], + validator=validate_stringlist, description="pan mnemonic" + ), + _Param( + "keymap.zoom", + default=["o"], + validator=validate_stringlist, description="zoom mnemonic" + ), + _Param( + "keymap.save", + default=["s", "ctrl+s"], + validator=validate_stringlist, + description="saving current figure" + ), + _Param( + "keymap.help", + default=["f1"], + validator=validate_stringlist, + description="display help about active tools" + ), + _Param( + "keymap.quit", + default=["ctrl+w", "cmd+w", "q"], + validator=validate_stringlist, + description="close the current figure" + ), + _Param( + "keymap.quit_all", + default=[], + validator=validate_stringlist, description="close all figures" + ), + _Param( + "keymap.grid", + default=["g"], + validator=validate_stringlist, + description="switching on/off major grids in current axes" + ), + _Param( + "keymap.grid_minor", + default=["G"], + validator=validate_stringlist, + description="switching on/off minor grids in current axes" + ), + _Param( + "keymap.yscale", + default=["l"], + validator=validate_stringlist, + description="toggle scaling of y-axes ('log'/'linear')" + ), + _Param( + "keymap.xscale", + default=["k", "L"], + validator=validate_stringlist, + description="toggle scaling of x-axes ('log'/'linear')" + ), + _Param( + "keymap.copy", + default=["ctrl+c", "cmd+c"], + validator=validate_stringlist, + description="copy figure to clipboard" + ), + _Section("Animation"), + _Param( + "animation.html", + default="none", + validator=["html5", "jshtml", "none"], + description="How to display the animation as HTML in the IPython notebook: " + "- 'html5' uses HTML5 video tag " + "- 'jshtml' creates a JavaScript animation" + ), + _Param( + "animation.writer", + default="ffmpeg", + validator=validate_string, + description="MovieWriter 'backend' to use" + ), + _Param( + "animation.codec", + default="h264", + validator=validate_string, + description="Codec to use for writing movie" + ), + _Param( + "animation.bitrate", + default=-1, + validator=validate_int, + description="Controls size/quality trade-off for movie. -1 implies let " + "utility auto-determine" + ), + _Param("animation.frame_format", "png", + ["png", "jpeg", "tiff", "raw", "rgba", "ppm", "sgi", "bmp", "pbm", "svg"], + description="Controls frame format used by temp files" + ), + _Param( + "animation.ffmpeg_path", + default="ffmpeg", + validator=_validate_pathlike, + description="Path to ffmpeg binary. Unqualified paths are resolved by " + "subprocess.Popen." + ), + _Param( + "animation.ffmpeg_args", + default=[], + validator=validate_stringlist, + description="Additional arguments to pass to ffmpeg" + ), + _Param( + "animation.convert_path", + default="convert", + validator=_validate_pathlike, + description="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)." + ), + _Param( + "animation.convert_args", + default=["-layers", "OptimizePlus"], + validator=validate_stringlist, + description="Additional arguments to pass to convert" + ), + _Param( + "animation.embed_limit", + default=20.0, + validator=validate_float, + description="Limit, in MB, of size of base64 encoded animation in HTML (i.e. " + "IPython notebook)" + ), + _Param( + "_internal.classic_mode", + default=False, + validator=validate_bool + ), + _Param("backend", None, validate_backend), +] + + +def _params_list(): + return [elem for elem in _DEFINITION if isinstance(elem, _Param)] diff --git a/lib/matplotlib/rcsetup.pyi b/lib/matplotlib/rcsetup.pyi new file mode 100644 index 000000000000..120c0c93bec9 --- /dev/null +++ b/lib/matplotlib/rcsetup.pyi @@ -0,0 +1,160 @@ +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_intlist(s: Any) -> list[int]: ... +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_color_or_None(s: Any) -> ColorType | None: ... +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_linestyle_or_None(s: Any) -> LineStyleType | None: ... +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 b5f8e735e066..637cfc849f9d --- a/lib/matplotlib/sankey.py +++ b/lib/matplotlib/sankey.py @@ -1,49 +1,19 @@ -#!/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 - -# 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"] @@ -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], @@ -227,12 +204,12 @@ def _arc(self, quadrant=0, cw=True, radius=1, center=(0, 0)): # Insignificant # [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 = [] @@ -374,94 +347,94 @@ def _revert(self, path, first_action=Path.LINETO): # 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,7 +554,7 @@ 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 @@ -594,7 +564,7 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', 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 @@ -614,7 +584,7 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', for i, (angle, is_input, spec) in enumerate(zip( 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: @@ -660,7 +630,7 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', 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. @@ -670,7 +640,7 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', 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 @@ -693,7 +663,7 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', 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: + 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..083d590559ca --- /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 import Self + +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 69158ad8b23f..a4cce23562d3 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -1,60 +1,187 @@ -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 math +import textwrap +from functools import wraps import numpy as np -from numpy import ma -from matplotlib.cbook import dedent -from matplotlib.ticker import (NullFormatter, ScalarFormatter, - LogFormatterMathtext, LogitFormatter) -from matplotlib.ticker import (NullLocator, LogLocator, AutoLocator, - SymmetricalLogLocator, LogitLocator) +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` - - :meth:`set_default_locators_and_formatters` + 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 the first argument. + + .. deprecated:: 3.11 + + The *axis* parameter is now optional, i.e. matplotlib is compatible + with `.ScaleBase` subclasses that do not take an *axis* parameter. + + The *axis* parameter is pending-deprecated. It will be deprecated + in matplotlib 3.13, and removed in matplotlib 3.15. + + 3rd-party scales are recommended to remove the *axis* parameter now + if they can afford to restrict compatibility to matplotlib >= 3.11 + already. Otherwise, they may keep the *axis* parameter and remove it + in time for matplotlib 3.13. + """ - And optionally: - - :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 + def val_in_range(self, val): + """ + Return whether the value(s) are within the valid range for this scale. + + This method is a generic implementation. Subclasses may implement more + efficient solutions for their domain. + """ + try: + if not math.isfinite(val): + return False + else: + vmin, vmax = self.limit_range_for_scale(val, val, minpos=1e-300) + return vmin == val and vmax == val + except (TypeError, ValueError): + return False + + +def _make_axis_parameter_optional(init_func): + """ + Decorator to allow leaving out the *axis* parameter in scale constructors. + + This decorator ensures backward compatibility for scale classes that + previously required an *axis* parameter. It allows constructors to be + called with or without the *axis* parameter. + + For simplicity, this does not handle the case when *axis* + is passed as a keyword. However, + scanning GitHub, there's no evidence that that is used anywhere. + + Parameters + ---------- + init_func : callable + The original __init__ method of a scale class. + + Returns + ------- + callable + A wrapped version of *init_func* that handles the optional *axis*. + + Notes + ----- + If the wrapped constructor defines *axis* as its first argument, the + parameter is preserved when present. Otherwise, the value `None` is injected + as the first argument. + + Examples + -------- + >>> from matplotlib.scale import ScaleBase + >>> class CustomScale(ScaleBase): + ... @_make_axis_parameter_optional + ... def __init__(self, axis, custom_param=1): + ... self.custom_param = custom_param + """ + @wraps(init_func) + def wrapper(self, *args, **kwargs): + sig = inspect.signature(init_func) + try: + # Try old signature. + sig.bind(self, *args, **kwargs) + except TypeError: + # Use the new signature and pass in an unused axis=None. + init_func(self, None, *args, **kwargs) + else: + # Use the old signature. + init_func(self, *args, **kwargs) + return wrapper + class LinearScale(ScaleBase): """ @@ -63,168 +190,185 @@ class LinearScale(ScaleBase): name = 'linear' - def __init__(self, axis, **kwargs): - pass + @_make_axis_parameter_optional + 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 val_in_range(self, val): + """ + Return whether the value is within the valid range for this scale. + + This is True for all values, except +-inf and NaN. + """ + return math.isfinite(val) + -def _mask_non_positives(a): +class FuncTransform(Transform): """ - Return a Numpy array where all non-positive values are - replaced with NaNs. 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 np.where(mask, np.nan, a) - return a - -def _clip_non_positives(a): - a = np.array(a, float) - 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) - return np.log10(a) + def transform_non_affine(self, values): + return self._forward(values) def inverted(self): - return InvertedLog10Transform() - + return FuncTransform(self._inverse, self._forward) -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 inverted(self): - return Log10Transform() - - -class Log2Transform(LogTransformBase): - base = 2.0 - - def transform_non_affine(self, a): - a = self._handle_nonpos(a * 2.0) - 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 FuncScale(ScaleBase): + """ + Provide an arbitrary scale with user-supplied function for the axis. + """ + name = 'function' -class NaturalLogTransform(LogTransformBase): - base = np.e + @_make_axis_parameter_optional + def __init__(self, axis, functions): + """ + Parameters + ---------- + axis : `~matplotlib.axis.Axis` + The axis for the scale. - def transform_non_affine(self, a): - a = self._handle_nonpos(a * np.e) - return np.log(a) + .. note:: + This parameter is unused and will be removed in an imminent release. + It can already be left out because of special preprocessing, + so that ``FuncScale(functions)`` is valid. - def inverted(self): - return InvertedNaturalLogTransform() + 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) - return np.log(a) / np.log(self.base) + self._clip = _api.getitem_checked( + {"clip": True, "mask": False}, nonpositive=nonpositive) + self._log_funcs = {np.e: np.log, 2: np.log2, 10: np.log10} + + 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_func = self._log_funcs.get(self.base) + if log_func: + out = log_func(values) + else: + out = np.log(values) / 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 + self._exp_funcs = {np.e: np.exp, 2: np.exp2} - 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): + exp_func = self._exp_funcs.get(self.base) + if exp_func: + return exp_func(values) + else: + return np.exp(values * np.log(self.base)) def inverted(self): return LogTransform(self.base) @@ -232,124 +376,141 @@ 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): - """ - *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. - """ - 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 + @_make_axis_parameter_optional + def __init__(self, axis=None, *, base=10, subs=None, nonpositive="clip"): + """ + Parameters + ---------- + axis : `~matplotlib.axis.Axis` + The axis for the scale. + + .. note:: + This parameter is unused and about to be removed in the future. + It can already now be left out because of special preprocessing, + so that ``LogScale(base=2)`` is valid. + + 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. + """ + 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) + + def val_in_range(self, val): + """ + Return whether the value is within the valid range for this scale. + + This is True for value(s) > 0 except +inf and NaN. + """ + return math.isfinite(val) and val > 0 + + +class FuncScaleLog(LogScale): + """ + Provide an arbitrary scale with user-supplied function for the axis and + then put on a logarithmic axes. + """ + + name = 'functionlog' + + @_make_axis_parameter_optional + def __init__(self, axis, functions, base=10): """ - Limit the domain to positive values. + Parameters + ---------- + axis : `~matplotlib.axis.Axis` + The axis for the scale. + + .. note:: + This parameter is unused and about to be removed in the future. + It can already now be left out because of special preprocessing, + so that ``FuncScaleLog(functions=(forward, inverse))`` is valid. + 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): + linscale_adj = self.linscale / (1.0 - 1.0 / self.base) + log_base = np.log(self.base) + + abs_a = np.abs(values) + inside = abs_a <= self.linthresh + if np.all(inside): # Fast path: all values in linear region + return values * linscale_adj + with np.errstate(divide="ignore", invalid="ignore"): + out = np.sign(values) * self.linthresh * ( + linscale_adj - np.log(self.linthresh) / log_base + + np.log(abs_a) / log_base) + out[inside] = values[inside] * linscale_adj + return out def inverted(self): return InvertedSymmetricalLogTransform(self.base, self.linthresh, @@ -357,31 +518,40 @@ 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) - symlog = SymmetricalLogTransform(base, linthresh, linscale) + 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.invlinthresh = symlog.transform(linthresh) 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 + + @_api.deprecated("3.11", name="invlinthresh", obj_type="attribute", + alternative=".inverted().transform(linthresh)") + @property + def invlinthresh(self): + invlinthresh = self.inverted().transform(self.linthresh) + return invlinthresh + + def transform_non_affine(self, values): + linscale_adj = self.linscale / (1.0 - 1.0 / self.base) + invlinthresh = self.inverted().transform(self.linthresh) + + abs_a = np.abs(values) + inside = abs_a <= invlinthresh + if np.all(inside): # Fast path: all values in linear region + return values / linscale_adj + with np.errstate(divide="ignore", invalid="ignore"): + out = np.sign(values) * self.linthresh * np.exp( + (abs_a / self.linthresh - linscale_adj) * np.log(self.base)) + out[inside] = values[inside] / linscale_adj + return out def inverted(self): return SymmetricalLogTransform(self.base, @@ -397,138 +567,246 @@ 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 + ---------- + axis : `~matplotlib.axis.Axis` + The axis for the scale. + + .. note:: + This parameter is unused and about to be removed in the future. + It can already now be left out because of special preprocessing, + so that ``SymmetricalLocSacle(base=2)`` is valid. + + 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 + @_make_axis_parameter_optional + def __init__(self, axis=None, *, 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 + + def val_in_range(self, val): """ - Return a :class:`SymmetricalLogTransform` instance. + Return whether the value is within the valid range for this scale. + + This is True for all values, except +-inf and NaN. """ - return self._transform + return math.isfinite(val) + + +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 _mask_non_logit(a): + 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): """ - Return a Numpy array where all values outside ]0, 1[ are - replaced with NaNs. If all values are inside ]0, 1[, the original - array is returned. + 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. """ - mask = (a <= 0.0) | (a >= 1.0) - if mask.any(): - return np.where(mask, np.nan, a) - return a + 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 _clip_non_logit(a): - a = np.array(a, float) - a[a <= 0.0] = 1e-300 - a[a >= 1.0] = 1 - 1e-300 - return a + @_make_axis_parameter_optional + def __init__(self, axis=None, *, linear_width=1.0, + base=10, subs='auto', **kwargs): + """ + Parameters + ---------- + axis : `~matplotlib.axis.Axis` + The axis for the scale. + + .. note:: + This parameter is unused and about to be removed in the future. + It can already now be left out because of special preprocessing, + so that ``AsinhScale()`` is valid. + + 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. + """ + 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) -class LogitTransform(Transform): - input_dims = 1 - output_dims = 1 - is_separable = True - has_inverse = True - - def __init__(self, nonpos): - Transform.__init__(self) - if nonpos == 'mask': - self._handle_nonpos = _mask_non_logit + 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: - self._handle_nonpos = _clip_non_logit - self._nonpos = nonpos + axis.set_major_formatter('{x:.3g}') + + def val_in_range(self, val): + """ + Return whether the value is within the valid range for this scale. + + This is True for all values, except +-inf and NaN. + """ + return math.isfinite(val) + + +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, a): + def transform_non_affine(self, values): """logit transform (base 10), masked or clipped""" - a = self._handle_nonpos(a) - return np.log10(1.0 * a / (1.0 - a)) + 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._nonpos) + return LogisticTransform(self._nonpositive) + + def __str__(self): + return f"{type(self).__name__}({self._nonpositive!r})" class LogisticTransform(Transform): - input_dims = 1 - output_dims = 1 - is_separable = True - has_inverse = True + input_dims = output_dims = 1 - def __init__(self, nonpos='mask'): - Transform.__init__(self) - self._nonpos = nonpos + def __init__(self, nonpositive='mask'): + super().__init__() + self._nonpositive = nonpositive - def transform_non_affine(self, a): + def transform_non_affine(self, values): """logistic transform (base 10)""" - return 1.0 / (1 + 10**(-a)) + return 1.0 / (1 + 10**(-values)) def inverted(self): - return LogitTransform(self._nonpos) + return LogitTransform(self._nonpositive) + + def __str__(self): + return f"{type(self).__name__}({self._nonpositive!r})" class LogitScale(ScaleBase): @@ -540,97 +818,170 @@ class LogitScale(ScaleBase): """ name = 'logit' - def __init__(self, axis, nonpos='mask'): - """ - *nonpos*: ['mask' | 'clip' ] - values beyond ]0, 1[ can be masked as invalid, or clipped to a number - very close to 0 or 1 + @_make_axis_parameter_optional + def __init__(self, axis=None, nonpositive='mask', *, + one_half=r"\frac{1}{2}", use_overline=False): + r""" + Parameters + ---------- + axis : `~matplotlib.axis.Axis` + The axis for the scale. + + .. note:: + This parameter is unused and about to be removed in the future. + It can already now be left out because of special preprocessing, + so that ``LogitScale()`` is valid. + + 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. """ - if nonpos not in ['mask', 'clip']: - raise ValueError("nonposx, nonposy kwarg must be 'mask' or 'clip'") - - self._transform = LogitTransform(nonpos) + self._transform = LogitTransform(nonpositive) + self._use_overline = use_overline + self._one_half = one_half def get_transform(self): - """ - Return a :class:`LogitTransform` instance. - """ + """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()) + 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()) + 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). """ - return (vmin <= 0 and minpos or vmin, - vmax >= 1 and (1 - minpos) or vmax) + 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) + + def val_in_range(self, val): + """ + Return whether the value is within the valid range for this scale. + + This is True for value(s) which are between 0 and 1 (excluded). + """ + return 0 < val < 1 _scale_mapping = { 'linear': LinearScale, 'log': LogScale, 'symlog': SymmetricalLogScale, + 'asinh': AsinhScale, 'logit': LogitScale, + 'function': FuncScale, + 'functionlog': FuncScaleLog, } +# caching of signature info +# For backward compatibility, the built-in scales will keep the *axis* parameter +# in their constructors until matplotlib 3.15, i.e. as long as the *axis* parameter +# is still supported. +_scale_has_axis_parameter = { + 'linear': True, + 'log': True, + 'symlog': True, + 'asinh': True, + 'logit': True, + 'function': True, + 'functionlog': True, +} + 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.getitem_checked(_scale_mapping, scale=scale) - if scale not in _scale_mapping: - raise ValueError("Unknown scale type '%s'" % scale) + if _scale_has_axis_parameter[scale]: + return scale_cls(axis, **kwargs) + else: + return scale_cls(**kwargs) - 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(): + # migration code to handle the *axis* parameter + has_axis_parameter = "axis" in inspect.signature(scale_class).parameters + _scale_has_axis_parameter[scale_class.name] = has_axis_parameter + if has_axis_parameter: + _api.warn_deprecated( + "3.11", + message=f"The scale {scale_class.__qualname__!r} uses an 'axis' parameter " + "in the constructors. This parameter is pending-deprecated since " + "matplotlib 3.11. It will be fully deprecated in 3.13 and removed " + "in 3.15. Starting with 3.11, 'register_scale()' accepts scales " + "without the *axis* parameter.", + pending=True, + ) + + +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..866509ee020d --- /dev/null +++ b/lib/matplotlib/scale.pyi @@ -0,0 +1,185 @@ +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]: ... + def val_in_range(self, val: float) -> bool: ... + +class LinearScale(ScaleBase): + name: str + def __init__( + self, + axis: Axis | None, + ) -> None: ... + +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 + linscale: float + @property + def invlinthresh(self) -> 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: ... +def _make_axis_parameter_optional(init_func: Callable[..., None]) -> Callable[..., 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/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 e9eff33bd8fd..7b46b3145e2b 100644 --- a/lib/matplotlib/sphinxext/plot_directive.py +++ b/lib/matplotlib/sphinxext/plot_directive.py @@ -1,183 +1,216 @@ """ -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: - - 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 conf.py - - 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. - - nofigs : bool - If specified, the code block will be run, but no figures will - be inserted. This is usually useful with the ``:context:`` - option. - -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`. +The ``.. plot::`` directive supports the following options: + +``:filename-prefix:`` : str + The base name (without the extension) of the outputted image and script + files. The default is to use the same name as the input script, or the + name of the RST document if no script is provided. The filename-prefix for + each plot directive must be unique. + +``:format:`` : {'python', 'doctest'} + The format of the input. If unset, the format is auto-detected. + +``: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). + +``: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). + +``: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. + +``: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. + +``:code-caption:`` : str + If specified, the option's argument will be used as a caption for the + code block (when ``:include-source:`` is used). This is added as the + ``:caption:`` option to the ``.. code-block::`` directive. + +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_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_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. +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*. - plot_template - Provide a customized template for preparing restructured text. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange -import sys, os, shutil, io, re, textwrap +from collections import defaultdict +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.environment.collectors import EnvironmentCollector +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): @@ -189,31 +222,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', 'close-figs']: return arg - raise ValueError("argument should be None or 'reset' or 'close-figs'") + 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] @@ -238,25 +265,53 @@ 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, + 'filename-prefix': directives.unchanged, + 'include-source': _option_boolean, + 'show-source-link': _option_boolean, + 'format': _option_format, + 'context': _option_context, + 'nofigs': directives.flag, + 'caption': directives.unchanged, + 'code-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) @@ -267,12 +322,45 @@ 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__} + app.connect('builder-inited', init_filename_registry) + app.add_env_collector(_FilenameCollector) + return metadata + + +# ----------------------------------------------------------------------------- +# Handle Duplicate Filenames +# ----------------------------------------------------------------------------- - app.connect(str('doctree-read'), mark_plot_labels) +def init_filename_registry(app): + env = app.builder.env + if not hasattr(env, 'mpl_plot_image_basenames'): + env.mpl_plot_image_basenames = defaultdict(set) -#------------------------------------------------------------------------------ + +class _FilenameCollector(EnvironmentCollector): + def process_doc(self, app, doctree): + pass + + def clear_doc(self, app, env, docname): + if docname in env.mpl_plot_image_basenames: + del env.mpl_plot_image_basenames[docname] + + def merge_other(self, app, env, docnames, other): + for docname in other.mpl_plot_image_basenames: + env.mpl_plot_image_basenames[docname].update( + other.mpl_plot_image_basenames[docname]) + + +# ----------------------------------------------------------------------------- # Doctest handling -#------------------------------------------------------------------------------ +# ----------------------------------------------------------------------------- + def contains_doctest(text): try: @@ -286,85 +374,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. - """ - sub_re = re.compile("^#\s*-\*-\s*coding:\s*.*-\*-$", flags=re.MULTILINE) - return sub_re.sub("", text) - -#------------------------------------------------------------------------------ +# ----------------------------------------------------------------------------- # 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 %} @@ -373,36 +475,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 }} - {% endfor %} - -{{ only_latex }} - - {% for img in images %} - {% if 'pdf' in img.formats -%} - .. image:: {{ build_dir }}/{{ img.basename }}.pdf - {% endif -%} + {{ caption }} {# appropriate leading whitespace added beforehand #} {% endfor %} -{{ only_texinfo }} +.. only:: not html {% 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>`__] @@ -414,34 +509,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. @@ -450,70 +558,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 @@ -524,61 +609,106 @@ 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, - close_figs=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 + + +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 + + +def check_output_base_name(env, output_base): + docname = env.docname + + if '.' in output_base or '/' in output_base or '\\' in output_base: + raise PlotError( + f"The filename-prefix '{output_base}' is invalid. " + f"It must not contain dots or slashes.") - # -- Try to determine if all images already exist + for d in env.mpl_plot_image_basenames: + if output_base in env.mpl_plot_image_basenames[d]: + if d == docname: + raise PlotError( + f"The filename-prefix {output_base!r} is used multiple times.") + raise PlotError(f"The filename-prefix {output_base!r} is used multiple" + f"times (it is also used in {env.doc2path(d)}).") - code_pieces = split_code_at_show(code) + env.mpl_plot_image_basenames[docname].add(output_base) + +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: @@ -588,6 +718,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 @@ -595,10 +727,7 @@ 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) @@ -613,7 +742,9 @@ def render_figures(code, code_path, output_dir, output_base, context, 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() @@ -626,12 +757,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)) @@ -642,15 +782,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 + env = document.settings.env + config = 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) + options.setdefault('show-source-link', config.plot_html_show_source_link) + options.setdefault('filename-prefix', None) + + 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'] @@ -664,28 +818,44 @@ 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() - output_base = os.path.basename(source_file_name) + code = Path(source_file_name).read_text(encoding='utf-8') + if options['filename-prefix']: + output_base = options['filename-prefix'] + check_output_base_name(env, output_base) + else: + output_base = os.path.basename(source_file_name) else: source_file_name = rst_file code = textwrap.dedent("\n".join(map(str, content))) - counter = document.attributes.get('_plot_counter', 0) + 1 - document.attributes['_plot_counter'] = counter - base, ext = os.path.splitext(os.path.basename(source_file_name)) - output_base = '%s-%d.py' % (base, counter) + if options['filename-prefix']: + output_base = options['filename-prefix'] + check_output_base_name(env, output_base) + else: + base, ext = os.path.splitext(os.path.basename(source_file_name)) + counter = document.attributes.get('_plot_counter', 0) + 1 + document.attributes['_plot_counter'] = counter + 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'): @@ -706,9 +876,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), @@ -718,58 +886,83 @@ 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 or '.py')).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, - keep_context, - function_name, - config, + 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') + 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'] + if 'code-caption' in options: + code_caption = options['code-caption'].replace('\n', ' ') + lines.append(f' :caption: {code_caption}') + lines.extend(['', *textwrap.indent(code_piece, ' ').splitlines()]) source_code = "\n".join(lines) else: source_code = "" @@ -777,59 +970,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 or '.py') 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..0b696f830543 --- /dev/null +++ b/lib/matplotlib/sphinxext/roles.py @@ -0,0 +1,165 @@ +""" +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) + + +# We sometimes want to use special notation in rcParam references, e.g. +# to use wildcards. This mapping maps such special notations to real rcParams, +# typically to the first relevant parameter in the group. +_RC_WILDCARD_LINK_MAPPING = { + "animation.[name-of-encoder]_args": "animation.ffmpeg_args", + "figure.subplot.*": "figure.subplot.left", + "figure.subplot.[name]": "figure.subplot.left", + "font.*": "font.family", + "lines.*": "lines.linewidth", + "patch.*": "patch.edgecolor", + "grid.major.*": "grid.major.color", + "grid.minor.*": "grid.minor.color", + "grid.*": "grid.color", +} + + +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}"]' + rc_param_name = _RC_WILDCARD_LINK_MAPPING.get(text, text) + target = f'rcparam_{rc_param_name.replace(".", "_")}' + 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/sphinxext/tests/__init__.py b/lib/matplotlib/sphinxext/tests/__init__.py deleted file mode 100644 index 7a8947f7fb9b..000000000000 --- a/lib/matplotlib/sphinxext/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Make tests a package diff --git a/lib/matplotlib/sphinxext/tests/test_tinypages.py b/lib/matplotlib/sphinxext/tests/test_tinypages.py deleted file mode 100644 index 2e78ec88f7f0..000000000000 --- a/lib/matplotlib/sphinxext/tests/test_tinypages.py +++ /dev/null @@ -1,85 +0,0 @@ -""" Tests for tinypages build using sphinx extensions """ - -import shutil -import tempfile - -from os.path import (join as pjoin, dirname, isdir) - -from subprocess import call, Popen, PIPE - -from nose import SkipTest -from nose.tools import assert_true - -HERE = dirname(__file__) -TINY_PAGES = pjoin(HERE, 'tinypages') - - -def setup(): - # Check we have the sphinx-build command - try: - ret = call(['sphinx-build', '--help'], stdout=PIPE, stderr=PIPE) - except OSError: - raise SkipTest('Need sphinx-build on path for these tests') - if ret != 0: - raise RuntimeError('sphinx-build does not return 0') - - -def file_same(file1, file2): - with open(file1, 'rb') as fobj: - contents1 = fobj.read() - with open(file2, 'rb') as fobj: - contents2 = fobj.read() - return contents1 == contents2 - - -class TestTinyPages(object): - # Test build and output of tinypages project - - @classmethod - def setup_class(cls): - cls.page_build = tempfile.mkdtemp() - try: - cls.html_dir = pjoin(cls.page_build, 'html') - cls.doctree_dir = pjoin(cls.page_build, 'doctrees') - # Build the pages with warnings turned into errors - cmd = ['sphinx-build', '-W', '-b', 'html', - '-d', cls.doctree_dir, - TINY_PAGES, - cls.html_dir] - proc = Popen(cmd, stdout=PIPE, stderr=PIPE) - out, err = proc.communicate() - except Exception as e: - shutil.rmtree(cls.page_build) - raise e - if proc.returncode != 0: - shutil.rmtree(cls.page_build) - raise RuntimeError('sphinx-build failed with stdout:\n' - '{0}\nstderr:\n{1}\n'.format( - out, err)) - - @classmethod - def teardown_class(cls): - shutil.rmtree(cls.page_build) - - def test_some_plots(self): - assert_true(isdir(self.html_dir)) - - def plot_file(num): - return pjoin(self.html_dir, 'some_plots-{0}.png'.format(num)) - - range_10, range_6, range_4 = [plot_file(i) for i in range(1, 4)] - # Plot 5 is range(6) plot - assert_true(file_same(range_6, plot_file(5))) - # Plot 7 is range(4) plot - assert_true(file_same(range_4, plot_file(7))) - # Plot 11 is range(10) plot - assert_true(file_same(range_10, plot_file(11))) - # Plot 12 uses the old range(10) figure and the new range(6) figure - assert_true(file_same(range_10, plot_file('12_00'))) - assert_true(file_same(range_6, plot_file('12_01'))) - # Plot 13 shows close-figs in action - assert_true(file_same(range_4, plot_file(13))) - # Plot 14 has included source - with open(pjoin(self.html_dir, 'some_plots.html'), 'rt') as fobj: - html_contents = fobj.read() - assert_true('# Only a comment' in html_contents) diff --git a/lib/matplotlib/sphinxext/tests/tinypages/.gitignore b/lib/matplotlib/sphinxext/tests/tinypages/.gitignore deleted file mode 100644 index 69fa449dd96e..000000000000 --- a/lib/matplotlib/sphinxext/tests/tinypages/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_build/ diff --git a/lib/matplotlib/sphinxext/tests/tinypages/conf.py b/lib/matplotlib/sphinxext/tests/tinypages/conf.py deleted file mode 100644 index d2d26c18eceb..000000000000 --- a/lib/matplotlib/sphinxext/tests/tinypages/conf.py +++ /dev/null @@ -1,264 +0,0 @@ -# -*- coding: utf-8 -*- -# -# tinypages documentation build configuration file, created by -# sphinx-quickstart on Tue Mar 18 11:58:34 2014. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -from os.path import join as pjoin, abspath -import sphinx -from distutils.version import LooseVersion - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) -sys.path.insert(0, abspath(pjoin('..', '..'))) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# 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.plot_directive'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'tinypages' -copyright = u'2014, Matplotlib developers' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '0.1' -# The full version, including alpha/beta/rc tags. -release = '0.1' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#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 - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -if LooseVersion(sphinx.__version__) >= LooseVersion('1.3'): - html_theme = 'classic' -else: - html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# 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, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# 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 - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'tinypagesdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'tinypages.tex', u'tinypages Documentation', - u'Matplotlib developers', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'tinypages', u'tinypages Documentation', - [u'Matplotlib developers'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'tinypages', u'tinypages Documentation', - u'Matplotlib developers', 'tinypages', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False diff --git a/lib/matplotlib/sphinxext/tests/tinypages/index.rst b/lib/matplotlib/sphinxext/tests/tinypages/index.rst deleted file mode 100644 index 3905483a8a57..000000000000 --- a/lib/matplotlib/sphinxext/tests/tinypages/index.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. tinypages documentation master file, created by - sphinx-quickstart on Tue Mar 18 11:58:34 2014. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to tinypages's documentation! -===================================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - some_plots - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/lib/matplotlib/sphinxext/tests/tinypages/some_plots.rst b/lib/matplotlib/sphinxext/tests/tinypages/some_plots.rst deleted file mode 100644 index d80b8c43f56b..000000000000 --- a/lib/matplotlib/sphinxext/tests/tinypages/some_plots.rst +++ /dev/null @@ -1,116 +0,0 @@ -########## -Some plots -########## - -Plot 1 does not use context: - -.. plot:: - - plt.plot(range(10)) - a = 10 - -Plot 2 doesn't use context either; has length 6: - -.. plot:: - - plt.plot(range(6)) - -Plot 3 has length 4: - -.. plot:: - - plt.plot(range(4)) - -Plot 4 shows that a new block with context does not see the variable defined -in the no-context block: - -.. plot:: - :context: - - assert 'a' not in globals() - -Plot 5 defines ``a`` in a context block: - -.. plot:: - :context: - - plt.plot(range(6)) - a = 10 - -Plot 6 shows that a block with context sees the new variable. It also uses -``:nofigs:``: - -.. plot:: - :context: - :nofigs: - - assert a == 10 - b = 4 - -Plot 7 uses a variable previously defined in previous ``nofigs`` context. It -also closes any previous figures to create a fresh figure: - -.. plot:: - :context: close-figs - - assert b == 4 - plt.plot(range(b)) - -Plot 8 shows that a non-context block still doesn't have ``a``: - -.. plot:: - :nofigs: - - assert 'a' not in globals() - -Plot 9 has a context block, and does have ``a``: - -.. plot:: - :context: - :nofigs: - - assert a == 10 - -Plot 10 resets context, and ``a`` has gone again: - -.. plot:: - :context: reset - :nofigs: - - assert 'a' not in globals() - c = 10 - -Plot 11 continues the context, we have the new value, but not the old: - -.. plot:: - :context: - - assert c == 10 - assert 'a' not in globals() - plt.plot(range(c)) - -Plot 12 opens a new figure. By default the directive will plot both the first -and the second figure: - -.. plot:: - :context: - - plt.figure() - plt.plot(range(6)) - -Plot 13 shows ``close-figs`` in action. ``close-figs`` closes all figures -previous to this plot directive, so we get always plot the figure we create in -the directive: - -.. plot:: - :context: close-figs - - plt.figure() - plt.plot(range(4)) - -Plot 14 uses ``include-source``: - -.. plot:: - :include-source: - - # Only a comment diff --git a/lib/matplotlib/spines.py b/lib/matplotlib/spines.py index 2673c46b92f2..35c1879a345c 100644 --- a/lib/matplotlib/spines.py +++ b/lib/matplotlib/spines.py @@ -1,63 +1,63 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +from collections.abc import MutableMapping +import functools -import six - -import matplotlib +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 - -rcParams = matplotlib.rcParams 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 @@ -65,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,290 +206,252 @@ def _ensure_position_is_set(self): self._position = ('outward', 0.0) # in points self.set_position(self._position) + def _ensure_transform_is_set(self): + # Install the default blended transform if the spine still carries + # the placeholder from Spine.__init__. Restricted to the standard + # cartesian spines: set_position/get_spine_transform only support + # those, and other spines (polar, cartopy's GeoSpine) manage their + # own transform. + if (self.spine_type in ('left', 'right', 'top', 'bottom') + and self._position is None + and self._transform is self.axes.transData): + self.set_position(('outward', 0.0)) + 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 + self.stale = True + + def clear(self): + """Clear the current spine.""" + self._clear() if self.axis is not None: - self.axis.cla() + self.axis.clear() + + def _clear(self): + """ + Clear things directly related to the spine. - def cla(self): - """Clear the current spine""" + 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._position = None # clear position - if self.axis is not None: - self.axis.cla() - def is_frame_like(self): - """return True if directly on axes frame + def _get_bounds_or_viewLim(self): + """ + Get the bounds of 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. + If self._bounds is None, return self.axes.viewLim.intervalx + or self.axes.viewLim.intervaly based on self.spine_type """ - 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 + 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: - return False + raise ValueError(f'spine_type: {self.spine_type} not supported') + return low, high 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 + low, high = self._get_bounds_or_viewLim() + + 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] + self._path = mpath.Path.arc(np.rad2deg(low), np.rad2deg(high)) + + if self.spine_type == 'bottom': + if self.axis is None: + tr = mtransforms.IdentityTransform() 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] + tr = self.axis.get_transform() + rmin, rmax = tr.transform(self.axes.viewLim.intervaly) + try: + rorigin = self.axes.get_rorigin() + except AttributeError: + rorigin = rmin else: - # No tick is available - high = datalim_high - high = min(high, viewlim_high) - - else: - low, high = self._bounds + rorigin = tr.transform(rorigin) + 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. + + 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) - def set_bounds(self, low, high): - """Set the bounds of the spine.""" + 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_viewLim() + 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.""" @@ -437,28 +459,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) @@ -469,13 +498,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..25bb2f45a0c4 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 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 cbook, collections, _api, _style_helpers +__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, 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. + + data : indexable object, optional + DATA_PARAMETER_PLACEHOLDER + + **kwargs + All other keyword arguments are passed to `.Axes.fill_between`. The + following parameters additionally accept a sequence of values + corresponding to the *y* datasets: + + - *hatch* + - *edgecolor* + - *facecolor* + - *linewidth* + - *linestyle* + + .. versionadded:: 3.9 + Allowing a sequence of strings for *hatch*. + + .. versionadded:: 3.11 + Allowing sequences of values in above listed `.Axes.fill_between` + parameters. + + 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) + y = np.vstack(args) + + labels = iter(labels) + if colors is None: + colors = [axes._get_lines.get_next_color() for _ in y] - labels = iter(kwargs.pop('labels', [])) + kwargs = cbook.normalize_kwargs(kwargs, collections.PolyCollection) + kwargs.setdefault('facecolor', colors) - colors = kwargs.pop('colors', None) - if colors is not None: - axes.set_color_cycle(colors) + kwargs, style_gen = _style_helpers.style_generator(kwargs) - 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,36 @@ 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, :], + label=next(labels, None), + **next(style_gen), **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), - **kwargs)) + label=next(labels, None), + **next(style_gen), **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..725fff7b23fd 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, colorizer, 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 = colorizer._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..80c6de00a18d 100644 --- a/lib/matplotlib/style/__init__.py +++ b/lib/matplotlib/style/__init__.py @@ -1,3 +1,253 @@ -from __future__ import absolute_import +""" +Core functions and attributes for the matplotlib style library: -from .core import use, context, available, library, reload_library +``use`` + Select style sheet to override the current matplotlib settings. +``context`` + Context manager to use a style sheet temporarily. +``available`` + List available style sheets. Underscore-prefixed names are considered private and + not listed, though may still be accessed directly from ``library``. +``library`` + A dictionary of style names and matplotlib settings. +""" + +import contextlib +import importlib.resources +import logging +import os +from pathlib import Path +import warnings + +import matplotlib as mpl +from matplotlib import _api, _docstring, rc_params_from_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')] +_STYLE_EXTENSION = 'mplstyle' +# 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. + + The style name of 'default' is reserved for reverting back to + the default style settings. + + .. note:: + + This updates the `.rcParams` with the settings from the style. + `.rcParams` not defined in the style are kept. + + Parameters + ---------- + 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. + + 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_from_file(path, use_default_template=False) + 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: + style = rc_params_from_file(style, use_default_template=False) + 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(style, after_reset=False): + """ + Context manager for using style settings temporarily. + + Parameters + ---------- + 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. + """ + 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 map(os.path.expanduser, USER_LIBRARY_PATHS): + styles = _read_style_directory(stylelib_path) + _update_nested_dict(library, styles) + return library + + +@_api.deprecated("3.11") +def update_user_library(library): + return _update_user_library(library) + + +def _read_style_directory(style_dir): + """Return dictionary of styles defined in *style_dir*.""" + styles = dict() + for path in Path(style_dir).glob(f"*.{_STYLE_EXTENSION}"): + with warnings.catch_warnings(record=True) as warns: + styles[path.stem] = rc_params_from_file(path, use_default_template=False) + for w in warns: + _log.warning('In %s: %s', path, w.message) + return styles + + +@_api.deprecated("3.11") +def read_style_directory(style_dir): + return _read_style_directory(style_dir) + + +def _update_nested_dict(main_dict, new_dict): + """ + Update nested dict (only level of nesting) with new values. + + 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 new_dict.items(): + main_dict.setdefault(name, {}).update(rc_dict) + return main_dict + + +@_api.deprecated("3.11") +def update_nested_dict(main_dict, new_dict): + return _update_nested_dict(main_dict, new_dict) + + +# Load style library +# ================== +_base_library = _read_style_directory(_BASE_LIBRARY_PATH) +library = {} +available = [] + + +def reload_library(): + """Reload the style library.""" + library.clear() + library.update(_update_user_library(_base_library.copy())) + available[:] = sorted(name for name in library if not name.startswith('_')) + + +reload_library() diff --git a/lib/matplotlib/style/__init__.pyi b/lib/matplotlib/style/__init__.pyi new file mode 100644 index 000000000000..c93b504fe6bd --- /dev/null +++ b/lib/matplotlib/style/__init__.pyi @@ -0,0 +1,20 @@ +from collections.abc import Generator +import contextlib + +from matplotlib import RcParams +from matplotlib.typing import RcStyleType + +USER_LIBRARY_PATHS: list[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/core.py b/lib/matplotlib/style/core.py index a67bc30c0859..c377bc64077a 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,181 +10,18 @@ ``library`` A dictionary of style names and matplotlib settings. """ -import os -import re -import contextlib - -import matplotlib as mpl -from matplotlib import cbook -from matplotlib import rc_params_from_file - - -__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')] -STYLE_EXTENSION = 'mplstyle' -STYLE_FILE_PATTERN = re.compile('([\S]+).%s$' % STYLE_EXTENSION) - - -def is_style_file(filename): - """Return True if the filename looks like a style file.""" - return STYLE_FILE_PATTERN.match(filename) is not None - - -def use(style): - """Use matplotlib style settings from a style specification. - - Parameters - ---------- - style : str, dict, or list - A style specification. Valid options are: - - +------+-------------------------------------------------------------+ - | str | The name of a style or a path/URL to a style file. For a | - | | list of available style names, see `style.available`. | - +------+-------------------------------------------------------------+ - | dict | Dictionary with valid key/value pairs for | - | | `matplotlib.rcParams`. | - +------+-------------------------------------------------------------+ - | list | A list of style specifiers (str or dict) applied from first | - | | to last in the list. | - +------+-------------------------------------------------------------+ - - - """ - if cbook.is_string_like(style) or hasattr(style, 'keys'): - # If name is a single str or dict, make it a single element list. - styles = [style] - else: - styles = style - - for style in styles: - if not cbook.is_string_like(style): - mpl.rcParams.update(style) - continue - - if style in library: - mpl.rcParams.update(library[style]) - else: - try: - rc = rc_params_from_file(style, use_default_template=False) - mpl.rcParams.update(rc) - except IOError: - 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 IOError(msg % style) - - -@contextlib.contextmanager -def context(style, after_reset=False): - """Context manager for using style settings temporarily. - - Parameters - ---------- - style : str, dict, or list - A style specification. Valid options are: - - +------+-------------------------------------------------------------+ - | str | The name of a style or a path/URL to a style file. For a | - | | list of available style names, see `style.available`. | - +------+-------------------------------------------------------------+ - | dict | Dictionary with valid key/value pairs for | - | | `matplotlib.rcParams`. | - +------+-------------------------------------------------------------+ - | list | A list of style specifiers (str or dict) 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() - try: - use(style) - except: - # Restore original settings before raising errors during the update. - mpl.rcParams.update(initial_settings) - raise - else: - yield - finally: - 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 - - -def update_user_library(library): - """Update style library with user-defined rc files""" - for stylelib_path in iter_user_libraries(): - 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`.""" - styles = dict() - for path, name in iter_style_files(style_dir): - styles[name] = rc_params_from_file(path, use_default_template=False) - return styles - - -def update_nested_dict(main_dict, new_dict): - """Update nested dict (only level of nesting) with new values. - - 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 - return main_dict - - -# Load style library -# ================== -_base_library = load_base_library() -library = None -available = [] +from .. import _api +from . import ( + use, context, available, library, reload_library, USER_LIBRARY_PATHS, + _BASE_LIBRARY_PATH as BASE_LIBRARY_PATH, + _STYLE_EXTENSION as STYLE_EXTENSION, + _STYLE_BLACKLIST as STYLE_BLACKLIST, +) +__all__ = [ + "use", "context", "available", "library", "reload_library", + "USER_LIBRARY_PATHS", "BASE_LIBRARY_PATH", "STYLE_EXTENSION", "STYLE_BLACKLIST", +] -def reload_library(): - """Reload style library.""" - global library, available - library = update_user_library(_base_library) - available[:] = library.keys() -reload_library() +_api.warn_deprecated("3.11", name=__name__, obj_type="module") diff --git a/lib/matplotlib/style/core.pyi b/lib/matplotlib/style/core.pyi new file mode 100644 index 000000000000..ee21d2f41ef5 --- /dev/null +++ b/lib/matplotlib/style/core.pyi @@ -0,0 +1,26 @@ +from collections.abc import Generator +import contextlib + +from matplotlib import RcParams +from matplotlib.typing import RcStyleType + +USER_LIBRARY_PATHS: list[str] = ... +BASE_LIBRARY_PATH: str = ... +STYLE_EXTENSION: str = ... +STYLE_BLACKLIST: set[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", + "USER_LIBRARY_PATHS", "BASE_LIBRARY_PATH", "STYLE_EXTENSION", "STYLE_BLACKLIST", +] diff --git a/lib/matplotlib/style/meson.build b/lib/matplotlib/style/meson.build new file mode 100644 index 000000000000..e7a183c8581c --- /dev/null +++ b/lib/matplotlib/style/meson.build @@ -0,0 +1,12 @@ +python_sources = [ + '__init__.py', + 'core.py', +] + +typing_sources = [ + '__init__.pyi', + '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..91dddba6c31f 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,120 @@ 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. + + .. note:: - Table can have (optional) row and column headers. + ``table()`` has some fundamental design limitations and will not be + developed further. If you need more functionality, consider + `blume `__. - Each entry in the table can be either text or patches. - Column widths and row heights for the table can be specifified. + The table consists of a grid of cells, which are indexed by (row, column). - Return value is a sequence of text, line and patch instances that make - up the table + 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. + + *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 +277,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 +479,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 +539,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`. + + >>> the_table.auto_set_font_size(False) + >>> the_table.set_fontsize(20) - for cell in six.itervalues(self._cells): + 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 +599,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 +610,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 +639,151 @@ 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`. + + .. note:: + + ``table()`` has some fundamental design limitations and will not be + developed further. If you need more functionality, consider + `blume `__. - 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 +802,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 +816,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 +835,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 +843,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 +851,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..3c7cc76c5570 100644 --- a/lib/matplotlib/testing/__init__.py +++ b/lib/matplotlib/testing/__init__.py @@ -1,2 +1,314 @@ -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'] = 'default' + + +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, **kwargs): + """ + 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.skip + If running on emscripten, which does not support subprocesses. + pytest.xfail + If platform is Cygwin and subprocess reports a fork() failure. + """ + if sys.platform == 'emscripten': + import pytest + pytest.skip('emscripten does not support subprocesses') + if capture_output: + stdout = stderr = subprocess.PIPE + # Add CREATE_NO_WINDOW flag on Windows to prevent console window overhead + # This is added in an attempt to fix flaky timeouts of subprocesses on Windows + if sys.platform == 'win32': + if 'creationflags' not in kwargs: + kwargs['creationflags'] = subprocess.CREATE_NO_WINDOW + else: + kwargs['creationflags'] |= subprocess.CREATE_NO_WINDOW + try: + proc = subprocess.run( + command, env=env, + timeout=timeout, check=check, + stdout=stdout, stderr=stderr, + text=text, **kwargs + ) + except BlockingIOError: + if sys.platform == "cygwin": + # Might want to make this more specific + import pytest + pytest.xfail("Fork failure") + raise + except subprocess.CalledProcessError as e: + if e.stdout: + _log.error(f"Subprocess output:\n{e.stdout}") + if e.stderr: + _log.error(f"Subprocess error:\n{e.stderr}") + raise e + if proc.stdout: + _log.debug(f"Subprocess output:\n{proc.stdout}") + if proc.stderr: + _log.debug(f"Subprocess error:\n{proc.stderr}") + 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", + # subprocess_run_helper sets SOURCE_DATE_EPOCH=0 above, so for a dirty tree, + # the version will have the date 19700101 which breaks pickle tests with a + # warning if the working tree is dirty. + # + # This will also avoid at least one additional subprocess call for + # setuptools-scm query git, so we tell the subprocess what version + # to report as the test process. + "SETUPTOOLS_SCM_PRETEND_VERSION_FOR_MATPLOTLIB": mpl.__version__, + **(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", "-no-shell-escape", + 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, OSError): + 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)] + non_basic_multilingual_plane = [chr(x) for x in range(0x1F600, 0x1F610)] + 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, + *non_basic_multilingual_plane], + 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..accf973615fa --- /dev/null +++ b/lib/matplotlib/testing/__init__.pyi @@ -0,0 +1,58 @@ +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 = ..., + **kwargs, +) -> 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 = ..., + **kwargs, +) -> 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 = ..., + **kwargs, +) -> 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 0495a7ae2f42..2b94847a72b6 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 -from matplotlib import cbook -from distutils import version +import matplotlib as mpl +from matplotlib import cbook, _image +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): + """ + An 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: - def cmd(old, new): - return [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: - def cmd(old, new): - return ['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,74 +411,84 @@ 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 - with the `.calculate_rms` function. + PNG via the `!converter` dictionary. The underlying RMS is calculated + in a similar way to 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 - extension = expected.split('.')[-1] - + expected = os.fspath(expected) if not os.path.exists(expected): - raise IOError('Baseline image %r does not exist.' % expected) - + raise OSError(f'Baseline image {expected!r} does not exist.') + extension = expected.split('.')[-1] if extension != 'png': - actual = convert(actual, False) - expected = convert(expected, True) + actual = convert(actual, cache=True) + expected = convert(expected, cache=True) - # 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] + # open the image files + expected_image = _load_image(expected) + actual_image = _load_image(actual) - actualImage, expectedImage = crop_to_same( - actual, actualImage, expected, expectedImage) + actual_image, expected_image = crop_to_same( + actual, actual_image, expected, expected_image) - # convert to signed integers, so that the images can be subtracted without - # overflow - expectedImage = expectedImage.astype(np.int16) - actualImage = actualImage.astype(np.int16) + diff_image = make_test_filename(actual, 'failed-diff') - rms = calculate_rms(expectedImage, actualImage) + if tol <= 0: + if np.array_equal(expected_image, actual_image): + return None - diff_image = make_test_filename(actual, 'failed-diff') + rms, abs_diff = _image.calculate_rms_and_diff(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) + Image.fromarray(abs_diff).save(diff_image, format="png") results = dict(rms=rms, expected=str(expected), actual=str(actual), diff=str(diff_image), tol=tol) @@ -350,29 +506,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..c60a38254aad --- /dev/null +++ b/lib/matplotlib/testing/conftest.py @@ -0,0 +1,199 @@ +import os +import sys + +import pytest + +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 high_memory(pytestconfig): + from matplotlib.testing import is_ci_environment + if not (os.environ.get('MPL_TEST_EXPENSIVE') or is_ci_environment()): + pytest.skip('Test uses too much memory') + + +@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_sfnt_table(font, name): + """ + Replace ``FT2Font.get_sfnt_table`` with empty results. + + This forces ``Text._get_layout`` to fall back to + ``get_text_width_height_descent``, which produces results from the patch below. + """ + return None + + 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.ft2font.FT2Font.get_sfnt_table', + patched_get_sfnt_table) + 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..df9f3bdeb36f --- /dev/null +++ b/lib/matplotlib/testing/conftest.pyi @@ -0,0 +1,16 @@ +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 high_memory(pytestconfig: pytest.Config) -> 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..c5f810f01f46 100644 --- a/lib/matplotlib/testing/decorators.py +++ b/lib/matplotlib/testing/decorators.py @@ -1,331 +1,476 @@ -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 _api, _pylab_helpers, cbook, ft2font, pyplot as plt, ticker +from matplotlib.figure import Figure +from .compare import comparable_formats, compare_images, make_test_filename +from .exceptions import ImageComparisonFailure + + +@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") + + +def _check_freetype_version(ver): + if ver is None: + return True -def knownfailureif(fail_condition, msg=None, known_exception_class=None ): + 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: + 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:: - Assume a will fail if *fail_condition* is True. *fail_condition* - may also be False or the string 'indeterminate'. - - *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) + 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. """ - # 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() - try: - func(*args, **kwargs) - finally: - _do_cleanup(original_units_registry) - - return wrapped_function - + 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 + if sys.platform == 'emscripten': + raise OSError + 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, + style=None): + """ 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. - Keyword arguments: + Parameters + ---------- + baseline_images : list or None + A list of strings specifying the names of the images generated by + calls to `.Figure.savefig`. - *baseline_images*: list - A list of strings specifying the names of the images generated - by calls to :meth:`matplotlib.figure.savefig`. + 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. - *extensions*: [ None | list ] + extensions : None or list of str + The list of extensions to test, e.g. ``['png', 'pdf']``. - If *None*, default to all supported extensions. + If *None*, defaults to: png, pdf, and svg. - Otherwise, a list of extensions to test. For example ['png','pdf']. + 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. - *tol*: (default 13) + 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 : 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. + + freetype_version : str or tuple + The expected freetype version or range of versions for this test to + pass. + + 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. - *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. + This does not remove other, more deliberate, text, such as legends and + annotations. - *savefig_kwarg*: dict + savefig_kwarg : dict Optional arguments that are passed to the savefig method. - """ + style : str, dict, or list + The style(s) to apply to the image test. The test itself can also apply + additional styles if desired. - if baseline_images is None: - raise ValueError('baseline_images must be specified') + .. versionchanged:: 3.11 + This defaults to ``['classic', '_classic_test_patch']``, but will be + changing to ``'mpl20'`` as of Matplotlib 3.13. A warning is raised if not + explicitly passed. + """ + 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 style is None: + _api.warn_external( + 'The default for the style parameter of image_comparsion() will be ' + 'changing to "mpl20" in Matplotlib 3.13; explicitly pass style to continue ' + 'working as before and suppress this warning.') + style = ('classic', '_classic_test_patch') + 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) + fig_test = Figure() + fig_ref = Figure() + func(*args, fig_test=fig_test, fig_ref=fig_ref, **kwargs) + if len(fig_test.get_children()) == 1 and len(fig_ref.get_children()) == 1: + # no artists have been added. The only child is fig.patch. + raise RuntimeError("Both figures are empty. Make sure you are " + "plotting to fig_test or fig_ref.") + + 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 + ) + + 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..1738794d119a --- /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 | None = ..., +) -> 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/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..95869740ace2 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.getitem_checked(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.getitem_checked(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..d5b815d1fc67 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..c528ffb2537c --- /dev/null +++ b/lib/matplotlib/testing/widgets.py @@ -0,0 +1,120 @@ +""" +======================== +Widget testing utilities +======================== + +See also :mod:`matplotlib.tests.test_widgets`. +""" + +from unittest import mock + +from matplotlib import _api +from matplotlib.backend_bases import MouseEvent, KeyEvent +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 + + +@_api.deprecated("3.11", alternative="MouseEvent or KeyEvent") +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 + + +@_api.deprecated("3.11", alternative="callbacks.process(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`). + """ + ax = tool.ax + if key is not None: # Press key + KeyEvent._from_ax_coords("key_press_event", ax, start, key)._process() + # Click, move, and release mouse + MouseEvent._from_ax_coords("button_press_event", ax, start, 1)._process() + MouseEvent._from_ax_coords("motion_notify_event", ax, end, 1)._process() + MouseEvent._from_ax_coords("button_release_event", ax, end, 1)._process() + if key is not None: # Release key + KeyEvent._from_ax_coords("key_release_event", ax, end, key)._process() 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/lualatex.json b/lib/matplotlib/tests/baseline_images/dviread/lualatex.json new file mode 100644 index 000000000000..8f2d95017ec7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/dviread/lualatex.json @@ -0,0 +1 @@ +[{"text": [[5046272, 4128768, "A", "lmroman10-regular.otf", 9.96, {}], [5756027, 4128768, "L", "lmroman10-regular.otf", 9.96, {}], [5929697, 4012179, "A", "lmroman7-regular.otf", 6.97, {}], [6218125, 4128768, "T", "lmroman10-regular.otf", 9.96, {}], [6582045, 4269998, "E", "lmroman10-regular.otf", 9.96, {}], [6946425, 4128768, "X", "lmroman10-regular.otf", 9.96, {}], [7656180, 4128768, "d", "DejaVuSans.ttf", 9.96, {"extend": 1.25, "slant": 0.25, "embolden": 0.25}], [8072180, 4128768, "o", "DejaVuSans.ttf", 9.96, {"extend": 1.25, "slant": 0.25, "embolden": 0.25}], [8473140, 4128768, "c", "DejaVuSans.ttf", 9.96, {"extend": 1.25, "slant": 0.25, "embolden": 0.25}], [8833460, 4128768, ".", "DejaVuSans.ttf", 9.96, {"extend": 1.25, "slant": 0.25, "embolden": 0.25}]], "boxes": []}, {"text": [[13686374, 5056284, "\u03c0", "cmmi5.pfb", 4.98, {}], [13716923, 5390308, "2", "cmr5.pfb", 4.98, {}], [13355110, 5463127, "integraldisplay", "cmex10.pfb", 9.96, {}], [13406537, 7324364, "0", "cmr7.pfb", 6.97, {}], [14010471, 5627696, "parenleftBig", "cmex10.pfb", 9.96, {}], [14937513, 5911796, "x", "cmmi10.pfb", 9.96, {}], [14480510, 6804696, "s", "lmroman10-regular.otf", 9.96, {}], [14738721, 6804696, "i", "lmroman10-regular.otf", 9.96, {}], [14920911, 6804696, "n", "lmroman10-regular.otf", 9.96, {}], [15394516, 6804696, "x", "cmmi10.pfb", 9.96, {}], [15847715, 5627696, "parenrightBig", "cmex10.pfb", 9.96, {}], [16239111, 5763501, "2", "cmr7.pfb", 6.97, {}], [16642338, 6355152, "d", "lmroman10-regular.otf", 9.96, {}], [17006718, 6355152, "x", "cmmi10.pfb", 9.96, {}]], "boxes": [[13686374, 5130818, 26213, 284106], [14480510, 6204418, 26213, 1288562]]}] diff --git a/lib/matplotlib/tests/baseline_images/dviread/pdflatex.json b/lib/matplotlib/tests/baseline_images/dviread/pdflatex.json new file mode 100644 index 000000000000..4754b722aa58 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/dviread/pdflatex.json @@ -0,0 +1 @@ +[{"text": [[5046272, 4128768, "A", "cmr10.pfb", 9.96, {}], [5756246, 4128768, "L", "cmr10.pfb", 9.96, {}], [5929917, 3994421, "A", "cmr7.pfb", 6.97, {}], [6218464, 4128768, "T", "cmr10.pfb", 9.96, {}], [6582530, 4269852, "E", "cmr10.pfb", 9.96, {}], [6946620, 4128768, "X", "cmr10.pfb", 9.96, {}], [7656594, 4128768, "d", "cmr10.pfb", 9.96, {}], [8020684, 4128768, "o", "cmr10.pfb", 9.96, {}], [8366570, 4128768, "c", "cmr10.pfb", 9.96, {}], [8657841, 4128768, ".", "cmr10.pfb", 9.96, {}]], "boxes": []}, {"text": [[13686591, 5056284, "\u03c0", "cmmi5.pfb", 4.98, {}], [13717140, 5390308, "2", "cmr5.pfb", 4.98, {}], [13355327, 5463127, "integraldisplay", "cmex10.pfb", 9.96, {}], [13406754, 7324364, "0", "cmr7.pfb", 6.97, {}], [14010688, 5627696, "parenleftBig", "cmex10.pfb", 9.96, {}], [14937658, 5911796, "x", "cmmi10.pfb", 9.96, {}], [14480727, 6804696, "s", "cmr10.pfb", 9.96, {}], [14739230, 6804696, "i", "cmr10.pfb", 9.96, {}], [14921275, 6804696, "n", "cmr10.pfb", 9.96, {}], [15394589, 6804696, "x", "cmmi10.pfb", 9.96, {}], [15847788, 5627696, "parenrightBig", "cmex10.pfb", 9.96, {}], [16239184, 5763501, "2", "cmr7.pfb", 6.97, {}], [16642411, 6355152, "d", "cmr10.pfb", 9.96, {}], [17006501, 6355152, "x", "cmmi10.pfb", 9.96, {}]], "boxes": [[13686591, 5130818, 26213, 284106], [14480727, 6204418, 26213, 1288418]]}] 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..1db4f18ea98d 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 b506e44cd48b..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 8f2b7cad1ca0..25203d28051c 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 214729508539..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.svg +++ /dev/null @@ -1,740 +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 31706ee324a1..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 b8ed868df20c..a43db5bff5cb 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 57334eb244ab..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/axvspan_epoch.svg +++ /dev/null @@ -1,736 +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..542bc145ccf6 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..2dffb4a35b55 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..1f07545ad922 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..c77021d6dfb5 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 1afba9760bc1..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 932ab02ebcad..3860b73ca22f 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 fb863d5b7026..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/boxplot.svg +++ /dev/null @@ -1,454 +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..3675f801cc34 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..b10c0d22cb38 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 933a067b2d06..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 e2d51f755042..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 2d76ce3d06f5..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_whiskers.svg +++ /dev/null @@ -1,384 +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..784c0269d758 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 b407b2fd5644..22d7f5430f4c 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..513586b42250 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..9fedf7f41d80 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..1ab340a27017 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 0f4352580a4a..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 c48d0ab78ce2..30f857f5439a 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 92dd1e0fc504..677c6430c607 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 565f491810a6..beb9e916d821 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 4cd264aaa011..a8d3252c5ab9 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 602168b49f50..509d8f92b0a0 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 9328472eb8f1..26e76e8338cd 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/canonical.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/canonical.svg @@ -1,421 +1,518 @@ - - + + + + + + 2026-04-02T23:33:31.612880 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+g6b5bbf332, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - + - + - + - - - - + + + + + + + + + + + + + + + + - + - - - - - + + + + - - - - - +" transform="scale(0.015625)"/> + + + + + + - + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + - + - - - - + + + + - - - - - +" transform="scale(0.015625)"/> + + + + + - + - + + + + + + + + + + + + - + - - - - - - - - - + + + + + + + - + - + + + + + + + + + + + + - + - - - - - - + + + + + + + - + + + + + + - + + + + + + + + + + + + - + - - - - - - - - - + + + + + + + - - - + - - - - + + + + + + + + + + + + - - - - + - - - - - - + + + + + + + - + - + + + + + + + + + + + + - + - - - - - - + + + + + + + - + - - - - - - + - - - - - - + + + + + + + - - - - - - - + + - + - - - - - - + + + + + + + - - - - - - - + + - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - + + 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 eb54a69b8190..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 f6c4d4e3f950..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 b9408dddc7af..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/const_xy.svg +++ /dev/null @@ -1,1434 +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 67e374eb15ef..334e7eb8e3ed 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 bd1bbbecff6c..2ffece597ca7 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 edcf9d219184..f79b5632f71c 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.svg @@ -1,18621 +1,18625 @@ - - + + + + + + 2026-03-12T19:45:49.237181 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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 f72c0363d089..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 404b65f2b694..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 e7fcb9977d13..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,6770 +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 ba328791bf7c..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 780d1f1410dc..e66e7067eef9 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 32db3f18fd56..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_basic.svg +++ /dev/null @@ -1,1209 +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 30036fa5f637..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 71c2a1cecbb0..fbf4e99f85e9 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 175eeb9bd42f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_limits.svg +++ /dev/null @@ -1,1695 +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 cff1fc76d70c..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 12b225c2b033..0e8ee85a28c7 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 9f21a95c82b8..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.svg +++ /dev/null @@ -1,2406 +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 7b488be16e95..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 b4c010f68eeb..6f6179ec6360 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 358cdf9937cb..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_zorder.svg +++ /dev/null @@ -1,1053 +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..a831390647e5 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 d5eb2e334fe8..b69837954299 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 ec3ad7f1ce74..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 8f517b1a661f..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 a1262102b988..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.svg +++ /dev/null @@ -1,637 +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 1cce62af22b8..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 690e3d3fbc0f..d300993681b0 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 5dad9362d57e..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_001.svg +++ /dev/null @@ -1,608 +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 19d0484b971e..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 669b5cc4dd71..a5d532a6cc5d 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 197b465033af..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_002.svg +++ /dev/null @@ -1,924 +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 39fec81ad09d..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 c449d229341f..ad0e570afd68 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 2c2cbf3de7fd..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_003.svg +++ /dev/null @@ -1,924 +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 c75785d56c7c..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 bb7bb0909ba4..3cec5e5de795 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 534cdc887b1b..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_004.svg +++ /dev/null @@ -1,814 +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 baa9032539a9..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 30ef5680b5a6..1a302ad56950 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 8ca9869e8e29..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_005.svg +++ /dev/null @@ -1,816 +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..5f294ec64f93 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..7dc68e25fae6 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 c5e718dfef1b..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 bd9c952d7904..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 32e7c7514ed7..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist2d.svg +++ /dev/null @@ -1,460 +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 88bc2453c4b4..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 dff57d8e3236..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 33158d549e2b..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist2d_transpose.svg +++ /dev/null @@ -1,500 +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..68273e23a2c9 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 177c8fffe72f..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 7c3e0688244f..4aaf8551aa9b 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 2bfbac5d7f02..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_offset.svg +++ /dev/null @@ -1,675 +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 1ea072bdbfda..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 a489b4b0901b..e524ccaf7739 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 47b853594aec..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_bar.svg +++ /dev/null @@ -1,1572 +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 17bdc88b7245..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 6b696ee5d520..a9bf4abf95f7 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 b6ffb643cc63..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_normed.svg +++ /dev/null @@ -1,688 +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 7b5c9a380b7c..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 d0505a9fad7d..e5236c4b41c9 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 3dbab47eff89..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_step.svg +++ /dev/null @@ -1,562 +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 a45647b12f94..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 8a9092c65a16..e673c066cb9b 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 4a7b3a52a899..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled.svg +++ /dev/null @@ -1,602 +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 82205339f66b..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 0f2195d2593f..7350f908a21b 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 bd58f8a15b3a..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled_alpha.svg +++ /dev/null @@ -1,602 +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 b5f8aeb53c1b..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 9cb5f9ed1a5b..0b84f702fd53 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 10a48c0c270c..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_weights.svg +++ /dev/null @@ -1,621 +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 7086b4cc4a80..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 0a18c5cdf521..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 170505aaf54e..c451da4dce6f 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..224247f1611f 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..c7619a45e09e 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..9f14dddfd61a 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..f50aff2b4190 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..d6f4bb78250e 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..ba0ebee53d2c 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/imshow.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/imshow.svg @@ -1,206 +1,155 @@ - - + + + + + + 2026-01-30T01:51:17.751114 + image/svg+xml + + + Matplotlib v3.11.0.dev1729+g1f7cad29d, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - + + - + - - - - - - - - - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - - - - + - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - + - + - + - + - - + + 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 130330968ba2..f80bd4b76868 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 c2b00431795a..d7505003ba78 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 e5856107ea65..c1f98c3c72c1 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.svg @@ -1,770 +1,831 @@ - - + + + + + + 2026-03-12T19:45:26.730441 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - + + - + - - - - - - - - - + - - - - - + + + + + - - - - - - + - + - - - - - - + + + + + + - - - - - - + - + - - + + - - - - +" 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 14b1504620dd..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 f159e08501d3..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 d271bc10c066..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg +++ /dev/null @@ -1,645 +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 009d8e0cbc48..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 2cad60f2ed47..69e08632f555 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 ae7a20379ae5..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/markevery.svg +++ /dev/null @@ -1,1009 +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 6087ecd1e56a..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 3c8ce1392899..ffb59042caae 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 4cd771a6f360..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.svg +++ /dev/null @@ -1,1429 +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 53370471d5ea..37a3858c07f4 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 7602127de8fa..aaf3c34a90f8 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 d310d5317071..1c3495b6738f 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.svg @@ -1,575 +1,468 @@ - - + + + + + + 2026-04-02T23:43:35.136617 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+g0081dee59, 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)"/> + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - - - - + + + + + + + - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - + - + - - + + + - - - - +M 2253 4666 +L 3047 4666 +L 3047 1625 +L 3713 1625 +L 3713 1100 +L 3047 1100 +L 3047 0 +L 2419 0 +L 2419 1100 +L 313 1100 +L 313 1709 +L 2253 4666 +z +" 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..d51ec5ee80f0 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 83893144f509..c88b5938a999 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 3f0b7465f86e..eec055f76f19 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 d0cb5413b68d..7e085f62207b 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/offset_points.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/offset_points.svg @@ -1,661 +1,551 @@ - - + + + + + + 2026-04-02T23:33:30.019529 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+g6b5bbf332, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - + - + - - - - - - - - - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - - - - + - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + + + + + + + + + + + + + + + + - - - - - + + + + + - + + - + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + - - + + 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 6352900bef6d..bd103b297ecd 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 6352900bef6d..865b63185782 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 1cb414023cae..711ab8d327a9 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 295eb5e5318a..15111ae27089 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..bbd8e6c58eea 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 d7947048bde3..9e120c623c40 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 f61eacab2b08..be3ef834cdad 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 90a75c6d2cc0..46ed069ac4dd 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..d697478cb58c 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..a945e3f1c657 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 c0451b42b911..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 dda089a2b6ef..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 9939c820a04f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_axes.svg +++ /dev/null @@ -1,1737 +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 7e8048b0509a..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 4aed7d7beddd..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 9ba521b08153..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_coords.svg +++ /dev/null @@ -1,451 +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 bb3ea0a2b5c8..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 7ed55164e433..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 e9cf86bd4c87..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_rlabel_position.svg +++ /dev/null @@ -1,1271 +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 0d7835472a0b..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 8dc5121fd5e4..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 b8ce6cf6cad2..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_rmin.svg +++ /dev/null @@ -1,1867 +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 6f7a66d54f69..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 312e9bc466cc..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 03847d449827..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.svg +++ /dev/null @@ -1,1601 +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 54dbe7b563d3..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 ef884a4a8196..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 12c2408d470c..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_units.svg +++ /dev/null @@ -1,1715 +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 a171bdf701ce..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 0d3815e55d94..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 aaa8caf894a4..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_units_2.svg +++ /dev/null @@ -1,1825 +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 64818d47738f..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 6503c7624adc..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 904636543992..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_180.svg +++ /dev/null @@ -1,1368 +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 74016f23d890..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 921a4864b29b..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 944e84399685..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.svg +++ /dev/null @@ -1,1391 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 92e957bff8db..aecf607cbf72 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.svg @@ -10,154 +10,147 @@ - - - +" id="m01198f80e9" style="stroke:#000000;stroke-width:40.000000;"/> - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -166,94 +159,94 @@ L0 4" id="m3a68111ca7" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -261,7 +254,7 @@ L-4 0" id="m81ec2b1422" style="stroke:#000000;stroke-width:0.5;"/> - + 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..e6beb32ed024 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..f5b824f1a57f 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..08988e9190e5 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..c68d6e48852e 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..a61987893008 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 a668eaf674ee..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 4e695b6c5b2b..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 6731f0b1c4d3..0d10be01fec0 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/scatter.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/scatter.svg @@ -1,8 +1,8 @@ - - + + - - - - + - + - + +" 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 index 56ea6656125f..ff8dfabd88ea 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/scatter_marker.png 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..4e62975a0079 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 index 9325c02203e8..0d83bc7daad8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/set_get_ticklabels.png 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 f52c0df2d99a..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 463804c9c7a7..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 1a4116936975..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/shaped_data.svg +++ /dev/null @@ -1,1725 +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 134ff83173b3..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 e35c353f200f..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 f727c934d70b..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/single_date.svg +++ /dev/null @@ -1,1281 +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 e6a9c6dc88b6..3f1b4c37af42 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 0882d1711f0d..71fad09fb7ae 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 a3f1b5cc9c1d..b22331d7ba2c 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/single_point.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/single_point.svg @@ -1,1233 +1,766 @@ - - + + + + + + 2026-04-02T23:43:32.692531 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+g0081dee59, 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)"/> + + + + + + - - - - - - - - - - - + + - + - + - - - - - - - - - - + + + + + + - - - - - - - - - - - + + - + - + - - - - - - + + + + + + - - - - - - - - - - - + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - + + + + + + - - - - - - - - - - - - + + + - + - + - + - - - - - - + + + + + + - - - - - - - - - - - - + + + - + - + - + - - - - - + + + + + - - - - - - - - - - - - + + + - + - + - + - - - - - + + + + + - - - - - - - - - - - - + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - + + - - - - +" style="stroke: #1f77b4"/> + + + - - + + - - + + - - + + - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + - + - + - - - - - + + + + + + + + + - - - - - - - - - - - - + + + - + - + - + - - - - - - - - + + + + + + + + - - - - - - - - - - - - + + + - + - + - + - - + + - - - - - - +" transform="scale(0.015625)"/> + + + + + - - - - - - - - - - - - + + + - + - + - + - - - - - + + + + + - - - - - - - - - - - - + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + - + - + - - - - - + + + + + - - - - - - - - - - - - + + + - + - + - + - - - - - + + + + + - - - - - - - - - - - - + + + - + - + - + - - - - - + + + + + - - - - - - - - - - - - + + + - + - + - + - - - - - + + + + + - - - - - - - - - - - - + + + - + - + - + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + - - + + 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..2c458150af68 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..465a029c8e98 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..a766ce6f0e42 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..ffbaea3bfdfa 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..3406a1baf496 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..70e503305782 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..c3b484da7a24 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..0f54ea20b947 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..7c253e92f9f4 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..0d40e285c5c7 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..f11ccdc3fdce 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..c7ac679392e1 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 ec5714ee1c3e..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 87f90f776115..e787dea7ad41 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 83813f3dc030..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_image.svg +++ /dev/null @@ -1,665 +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 4490910edc97..a7f9fe438ffc 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 8abdc4f314e6..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 4c231f9b5bb2..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg +++ /dev/null @@ -1,690 +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..4b1797ddd4d3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_axes/test_centered_bar_label_nonlinear.svg @@ -0,0 +1,166 @@ + + + + + + + + 2026-04-02T23:33:42.122859 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+g6b5bbf332, 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..473d8ed624e3 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..32fdd5ac4ec2 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 c8073611a958..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 eb8b4f1f0388..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 4180d4eac2f6..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locaters_formatters.svg +++ /dev/null @@ -1,1271 +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..7874e0ccaf1a 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 19245acd6f63..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 3a9abdd61d90..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 2da024934fbd..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/units_strings.svg +++ /dev/null @@ -1,554 +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..24fb2e78b0ce 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 c386bd72d83b..428f30f461c6 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 f3178860b6df..c0e9285c43c6 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 38ffbd5d359d..9f8eb400519f 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 2aeb79b5c49c..acf0933d605d 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 140aae606458..0576b1be910b 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 b7c8bacd1b50..005e745e47f2 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 6307e2e2afc5..0139e077e425 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 00c7280f8538..b9163c54d9e8 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 2d8105c8f1b2..e058cbe788e9 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 92980f28750d..1735ab6f804d 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 8faadd80ccee..820c8ecde925 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 74a2fa96eaab..3c04ce8e3ef5 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 bcfa3481d02f..370f372a6bb3 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 55151d89013b..c8b50dca6185 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 44a95bbf6eb6..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 4f1a174af834..ac690c76edf8 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 955ec1e62d08..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/vline_hline_zorder.svg +++ /dev/null @@ -1,1036 +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..10d2f774379e 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..ac1d09cc95bf 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..27a884256f80 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..bbb899c4ea1b 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_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..5235e67edefd 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..a675c1d59818 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..6798177ebb90 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..b7dbb9adec70 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_backend_pdf/truetype-conversion.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/truetype-conversion.pdf new file mode 100644 index 000000000000..876edfde0d05 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/truetype-conversion.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type3.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type3.pdf new file mode 100644 index 000000000000..abba76f2960a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type3.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type42.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type42.pdf new file mode 100644 index 000000000000..e62a73a1fe13 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/ttc_type42.pdf differ 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..5f5c14f76dc2 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..5476885da6a7 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..d29201638b7b 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..a0d5872c9af4 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..349826ce9340 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..9d05f9e3e559 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..ae51c55ca505 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_pgf/ttc_pgf.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pgf/ttc_pgf.pdf new file mode 100644 index 000000000000..5d695e734577 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pgf/ttc_pgf.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..7aa442326ec7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/colorbar_shift.eps @@ -0,0 +1,925 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: colorbar_shift.eps +%%Creator: Matplotlib v3.11.0.dev2075+g5a13dc378e, https://matplotlib.org/ +%%CreationDate: Fri Mar 13 23:13:37 2026 +%%Orientation: portrait +%%BoundingBox: 0 0 392 302 +%%HiResBoundingBox: 0.000000 0.000000 391.773225 301.310828 +%%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 /DejaVuSans-0 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/zero /period /two /four /six /eight /one /nine /five] def +/CharStrings 10 dict dup begin +/.notdef 0 def +/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 +/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 +/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 +/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 +/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 +/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 +/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 +/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 +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-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /DejaVuSans-1 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/minus] def +/CharStrings 2 dict dup begin +/.notdef 0 def +/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 +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 +0 0 translate +0 0 391.773 301.311 rectclip +gsave +0 0 m +391.773225 0 l +391.773225 301.310828 l +0 301.310828 l +cl +1 setgray +fill +grestore +gsave +36.45 24.2 m +322.146 24.2 l +322.146 290.312 l +36.45 290.312 l +cl +1 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 setlinewidth +1 setlinejoin +0 setlinecap +[] 0 setdash +0 0.5 0 setrgbcolor +gsave +36.45 24.2 285.696 266.112 rectclip +49.4362 157.256 p0_0 +gsave +fill +grestore +stroke +grestore +0 0 1 setrgbcolor +gsave +36.45 24.2 285.696 266.112 rectclip +309.16 157.256 p0_0 +gsave +fill +grestore +stroke +grestore +0.8 setlinewidth +0 setgray +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +0 0 m +0 -3.5 l + +gsave +0 setgray +fill +grestore +stroke +grestore +} bind def +49.4362 24.2 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +41.4909 9.60234 translate +0 rotate +0 0 m /zero glyphshow +6.35938 0 m /period glyphshow +9.53125 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 setgray +fill +grestore +stroke +grestore +} bind def +101.381 24.2 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +93.4356 9.60234 translate +0 rotate +0 0 m /zero glyphshow +6.35938 0 m /period glyphshow +9.53125 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 setgray +fill +grestore +stroke +grestore +} bind def +153.326 24.2 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +145.38 9.60234 translate +0 rotate +0 0 m /zero glyphshow +6.35938 0 m /period glyphshow +9.53125 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 setgray +fill +grestore +stroke +grestore +} bind def +205.27 24.2 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +197.325 9.60234 translate +0 rotate +0 0 m /zero glyphshow +6.35938 0 m /period glyphshow +9.53125 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 setgray +fill +grestore +stroke +grestore +} bind def +257.215 24.2 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +249.27 9.60234 translate +0 rotate +0 0 m /zero glyphshow +6.35938 0 m /period glyphshow +9.53125 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 setgray +fill +grestore +stroke +grestore +} bind def +309.16 24.2 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +301.215 9.60234 translate +0 rotate +0 0 m /one glyphshow +6.35938 0 m /period glyphshow +9.53125 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 setgray +fill +grestore +stroke +grestore +} bind def +36.45 60.488 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +7.2 56.6892 translate +0 rotate +0 0 m /zero glyphshow +6.35938 0 m /period glyphshow +9.53125 0 m /nine glyphshow +15.8906 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 setgray +fill +grestore +stroke +grestore +} bind def +36.45 108.872 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +7.2 105.073 translate +0 rotate +0 0 m /zero glyphshow +6.35938 0 m /period glyphshow +9.53125 0 m /nine glyphshow +15.8906 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 setgray +fill +grestore +stroke +grestore +} bind def +36.45 157.256 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +7.2 153.457 translate +0 rotate +0 0 m /one glyphshow +6.35938 0 m /period glyphshow +9.53125 0 m /zero glyphshow +15.8906 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 setgray +fill +grestore +stroke +grestore +} bind def +36.45 205.64 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +7.2 201.841 translate +0 rotate +0 0 m /one glyphshow +6.35938 0 m /period glyphshow +9.53125 0 m /zero glyphshow +15.8906 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 setgray +fill +grestore +stroke +grestore +} bind def +36.45 254.024 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +7.2 250.225 translate +0 rotate +0 0 m /one glyphshow +6.35938 0 m /period glyphshow +9.53125 0 m /zero glyphshow +15.8906 0 m /four glyphshow +grestore +0 setlinejoin +2 setlinecap +gsave +36.45 24.2 m +36.45 290.312 l +stroke +grestore +gsave +322.146 24.2 m +322.146 290.312 l +stroke +grestore +gsave +36.45 24.2 m +322.146 24.2 l +stroke +grestore +gsave +36.45 290.312 m +322.146 290.312 l +stroke +grestore +gsave +340.002 24.2 m +353.3076 24.2 l +353.3076 290.312 l +340.002 290.312 l +cl +1 setgray +fill +grestore +gsave +340.002 24.2 13.306 266.112 rectclip +340.002 24.2 m +353.3076 24.2 l +353.3076 112.904 l +340.002 112.904 l +340.002 24.2 l +1 0 0 setrgbcolor +fill +grestore +gsave +340.002 24.2 13.306 266.112 rectclip +340.002 112.904 m +353.3076 112.904 l +353.3076 201.608 l +340.002 201.608 l +340.002 112.904 l +0 0.5 0 setrgbcolor +fill +grestore +gsave +340.002 24.2 13.306 266.112 rectclip +340.002 201.608 m +353.3076 201.608 l +353.3076 290.312 l +340.002 290.312 l +340.002 201.608 l +0 0 1 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 setgray +fill +grestore +stroke +grestore +} bind def +353.308 24.2 o +grestore +/DejaVuSans-1 10.000 selectfont +gsave + +360.308 20.4012 translate +0 rotate +0 0 m /minus glyphshow +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +360.308 20.4012 translate +0 rotate +8.375 0 m /one glyphshow +14.7344 0 m /period glyphshow +17.9062 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 setgray +fill +grestore +stroke +grestore +} bind def +353.308 112.904 o +grestore +/DejaVuSans-1 10.000 selectfont +gsave + +360.308 109.105 translate +0 rotate +0 0 m /minus glyphshow +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +360.308 109.105 translate +0 rotate +8.375 0 m /zero glyphshow +14.7344 0 m /period glyphshow +17.9062 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 setgray +fill +grestore +stroke +grestore +} bind def +353.308 201.608 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +360.308 197.809 translate +0 rotate +0 0 m /zero glyphshow +6.35938 0 m /period glyphshow +9.53125 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 setgray +fill +grestore +stroke +grestore +} bind def +353.308 290.312 o +grestore +/DejaVuSans-0 10.000 selectfont +gsave + +360.308 286.513 translate +0 rotate +0 0 m /one glyphshow +6.35938 0 m /period glyphshow +9.53125 0 m /zero glyphshow +grestore +0 setlinejoin +2 setlinecap +gsave +340.002 24.2 m +346.6548 24.2 l +353.3076 24.2 l +353.3076 290.312 l +346.6548 290.312 l +340.002 290.312 l +340.002 24.2 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..72133caba911 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/multi_font_type3.eps @@ -0,0 +1,17198 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: multi_font_type3.eps +%%Creator: Matplotlib v3.11.0.dev2222+g4230aa142, https://matplotlib.org/ +%%CreationDate: Fri Apr 3 00:28:30 2026 +%%Orientation: portrait +%%BoundingBox: 0 0 576 432 +%%HiResBoundingBox: 0.000000 0.000000 576.000000 432.000000 +%%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 +/sc { setcachedevice } _d +%!PS-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /Cmr10-0 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-90 -512 2066 1536] def +/FontType 3 def +/Encoding [/T /h /e /r /space /a /b /s /i /c /t /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /U /V /W /X /Y /Z /d /f /g /j /k /l /m /n /o /p /q /u /v /w /x /y /z /zero /one /two /three /four /five /six /seven /eight /nine /exclam /quotedblright /numbersign /dollar /percent /ampersand /quoteright /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /colon /semicolon /exclamdown /equal /questiondown /question /at /bracketleft /quotedblleft /bracketright /circumflex /dotaccent /quoteleft /emdash /endash /hungarumlaut /tilde] def +/CharStrings 96 dict dup begin +/.notdef 0 def +/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 +/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 +/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 +/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 +/space{682 0 0 0 0 0 sc +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 +/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 +/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 +/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 +/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 +/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 +/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 +/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 +/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 +/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 +/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 +/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 +/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 +/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 +/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 +/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-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /DejaVuSans-0 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def +/CharStrings 60 dict dup begin +/.notdef 0 def +/Aring{1401 0 16 0 1384 1901 sc +852 1626 m +852 1668 837 1704 807 1733 c +778 1763 742 1778 700 1778 c +657 1778 621 1763 592 1734 c +563 1705 549 1669 549 1626 c +549 1584 564 1548 593 1519 c +622 1490 658 1475 700 1475 c +742 1475 778 1490 807 1519 c +837 1548 852 1584 852 1626 c + +700 1294 m +428 551 l +973 551 l +700 1294 l + +549 1397 m +508 1424 478 1457 457 1495 c +436 1534 426 1577 426 1626 c +426 1703 452 1768 505 1821 c +558 1874 623 1901 700 1901 c +776 1901 841 1874 894 1820 c +948 1767 975 1702 975 1626 c +975 1579 964 1536 943 1497 c +922 1458 892 1424 852 1397 c +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +549 1397 l + +ce} _d +/AE{1995 0 8 0 1864 1493 sc +1845 1493 m +1845 1323 l +1104 1323 l +1104 881 l +1815 881 l +1815 711 l +1104 711 l +1104 170 l +1864 170 l +1864 0 l +901 0 l +901 383 l +373 383 l +213 0 l +8 0 l +633 1493 l +1845 1493 l + +772 1335 m +442 551 l +901 551 l +901 1335 l +772 1335 l + +ce} _d +/Ccedilla{1430 0 115 -395 1319 1520 sc +1319 1378 m +1319 1165 l +1251 1228 1178 1276 1101 1307 c +1024 1338 943 1354 856 1354 c +685 1354 555 1302 464 1197 c +373 1093 328 942 328 745 c +328 548 373 398 464 293 c +555 189 685 137 856 137 c +943 137 1024 153 1101 184 c +1178 215 1251 263 1319 326 c +1319 115 l +1248 67 1173 31 1094 7 c +1015 -17 932 -29 844 -29 c +618 -29 440 40 310 178 c +180 317 115 506 115 745 c +115 985 180 1174 310 1312 c +440 1451 618 1520 844 1520 c +933 1520 1017 1508 1096 1484 c +1175 1461 1250 1425 1319 1378 c + +897 0 m +934 -41 961 -79 979 -114 c +997 -149 1006 -183 1006 -215 c +1006 -274 986 -319 946 -349 c +906 -380 847 -395 768 -395 c +737 -395 707 -393 678 -389 c +649 -385 621 -379 592 -371 c +592 -240 l +615 -251 638 -259 663 -264 c +688 -269 716 -272 747 -272 c +786 -272 816 -264 836 -248 c +856 -232 866 -209 866 -178 c +866 -158 859 -133 844 -104 c +830 -75 808 -41 778 0 c +897 0 l + +ce} _d +/Egrave{1294 0 201 0 1163 1899 sc +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +613 1899 m +809 1635 l +656 1635 l +426 1899 l +613 1899 l + +ce} _d +/Eacute{1294 0 201 0 1163 1899 sc +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +725 1899 m +910 1899 l +682 1635 l +529 1635 l +725 1899 l + +ce} _d +/Ecircumflex{1294 0 201 0 1163 1901 sc +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +576 1901 m +764 1901 l +975 1635 l +836 1635 l +670 1813 l +504 1635 l +365 1635 l +576 1901 l + +ce} _d +/Edieresis{1294 0 201 0 1163 1870 sc +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +764 1870 m +967 1870 l +967 1667 l +764 1667 l +764 1870 l + +373 1870 m +576 1870 l +576 1667 l +373 1667 l +373 1870 l + +ce} _d +/Igrave{604 0 59 0 442 1899 sc +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +246 1899 m +442 1635 l +289 1635 l +59 1899 l +246 1899 l + +ce} _d +/Iacute{604 0 162 0 543 1899 sc +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +358 1899 m +543 1899 l +315 1635 l +162 1635 l +358 1899 l + +ce} _d +/Icircumflex{604 0 -2 0 608 1901 sc +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +209 1901 m +397 1901 l +608 1635 l +469 1635 l +303 1813 l +137 1635 l +-2 1635 l +209 1901 l + +ce} _d +/Idieresis{604 0 6 0 600 1870 sc +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +397 1870 m +600 1870 l +600 1667 l +397 1667 l +397 1870 l + +6 1870 m +209 1870 l +209 1667 l +6 1667 l +6 1870 l + +ce} _d +/Eth{1587 0 10 0 1466 1493 sc +211 1493 m +627 1493 l +916 1493 1128 1433 1263 1312 c +1398 1192 1466 1004 1466 748 c +1466 491 1398 302 1262 181 c +1127 60 915 0 627 0 c +211 0 l +211 700 l +10 700 l +10 844 l +211 844 l +211 1493 l + +414 1327 m +414 844 l +750 844 l +750 700 l +414 700 l +414 166 l +657 166 l +863 166 1014 213 1109 306 c +1205 399 1253 547 1253 748 c +1253 948 1205 1094 1109 1187 c +1014 1280 863 1327 657 1327 c +414 1327 l + +ce} _d +/Ntilde{1532 0 201 0 1331 1886 sc +201 1493 m +473 1493 l +1135 244 l +1135 1493 l +1331 1493 l +1331 0 l +1059 0 l +397 1249 l +397 0 l +201 0 l +201 1493 l + +762 1710 m +705 1743 l +688 1752 675 1759 664 1762 c +654 1766 645 1768 637 1768 c +613 1768 594 1760 581 1743 c +568 1726 561 1703 561 1673 c +561 1667 l +436 1667 l +436 1734 453 1788 487 1827 c +522 1866 568 1886 625 1886 c +649 1886 671 1883 691 1878 c +712 1873 738 1861 770 1843 c +827 1813 l +842 1804 856 1798 867 1794 c +878 1790 889 1788 899 1788 c +920 1788 938 1796 951 1813 c +964 1830 971 1853 971 1880 c +971 1886 l +1096 1886 l +1095 1819 1077 1766 1042 1726 c +1008 1687 963 1667 907 1667 c +884 1667 863 1670 843 1675 c +824 1680 797 1692 762 1710 c + +ce} _d +/Ograve{1612 0 115 -29 1497 1899 sc +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +750 1899 m +946 1635 l +793 1635 l +563 1899 l +750 1899 l + +ce} _d +/Oacute{1612 0 115 -29 1497 1899 sc +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +862 1899 m +1047 1899 l +819 1635 l +666 1635 l +862 1899 l + +ce} _d +/Ocircumflex{1612 0 115 -29 1497 1901 sc +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +713 1901 m +901 1901 l +1112 1635 l +973 1635 l +807 1813 l +641 1635 l +502 1635 l +713 1901 l + +ce} _d +/Otilde{1612 0 115 -29 1497 1886 sc +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +803 1710 m +746 1743 l +729 1752 716 1759 705 1762 c +695 1766 686 1768 678 1768 c +654 1768 635 1760 622 1743 c +609 1726 602 1703 602 1673 c +602 1667 l +477 1667 l +477 1734 494 1788 528 1827 c +563 1866 609 1886 666 1886 c +690 1886 712 1883 732 1878 c +753 1873 779 1861 811 1843 c +868 1813 l +883 1804 897 1798 908 1794 c +919 1790 930 1788 940 1788 c +961 1788 979 1796 992 1813 c +1005 1830 1012 1853 1012 1880 c +1012 1886 l +1137 1886 l +1136 1819 1118 1766 1083 1726 c +1049 1687 1004 1667 948 1667 c +925 1667 904 1670 884 1675 c +865 1680 838 1692 803 1710 c + +ce} _d +/Odieresis{1612 0 115 -29 1497 1870 sc +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +901 1870 m +1104 1870 l +1104 1667 l +901 1667 l +901 1870 l + +510 1870 m +713 1870 l +713 1667 l +510 1667 l +510 1870 l + +ce} _d +/multiply{1716 0 281 63 1436 1221 sc +1436 1100 m +979 641 l +1436 184 l +1317 63 l +858 522 l +399 63 l +281 184 l +737 641 l +281 1100 l +399 1221 l +858 762 l +1317 1221 l +1436 1100 l + +ce} _d +/Oslash{1612 0 102 -70 1509 1559 sc +1206 1112 m +489 266 l +530 223 578 191 631 168 c +685 146 744 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 820 1277 888 1264 949 c +1251 1010 1232 1065 1206 1112 c + +1124 1225 m +1083 1268 1036 1300 982 1322 c +929 1345 870 1356 807 1356 c +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 670 334 602 347 539 c +360 476 380 422 406 377 c +1124 1225 l + +272 219 m +220 287 181 365 154 453 c +128 541 115 638 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c +894 1520 974 1507 1047 1481 c +1121 1456 1187 1418 1245 1368 c +1407 1559 l +1509 1470 l +1339 1272 l +1391 1203 1430 1125 1457 1036 c +1484 947 1497 850 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +722 -29 642 -17 568 8 c +495 33 428 71 367 121 c +205 -70 l +102 18 l +272 219 l + +ce} _d +/Ugrave{1499 0 178 -29 1321 1899 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +693 1899 m +889 1635 l +736 1635 l +506 1899 l +693 1899 l + +ce} _d +/Uacute{1499 0 178 -29 1321 1899 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +805 1899 m +990 1899 l +762 1635 l +609 1635 l +805 1899 l + +ce} _d +/Ucircumflex{1499 0 178 -29 1321 1901 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +656 1901 m +844 1901 l +1055 1635 l +916 1635 l +750 1813 l +584 1635 l +445 1635 l +656 1901 l + +ce} _d +/Udieresis{1499 0 178 -29 1321 1870 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +844 1870 m +1047 1870 l +1047 1667 l +844 1667 l +844 1870 l + +453 1870 m +656 1870 l +656 1667 l +453 1667 l +453 1870 l + +ce} _d +/Yacute{1251 0 -4 0 1255 1899 sc +-4 1493 m +213 1493 l +627 879 l +1038 1493 l +1255 1493 l +727 711 l +727 0 l +524 0 l +524 711 l +-4 1493 l + +682 1899 m +867 1899 l +639 1635 l +486 1635 l +682 1899 l + +ce} _d +/Thorn{1239 0 201 0 1165 1493 sc +201 1493 m +403 1493 l +403 1229 l +657 1229 l +824 1229 951 1191 1036 1116 c +1122 1041 1165 931 1165 784 c +1165 637 1122 526 1036 451 c +951 376 824 338 657 338 c +403 338 l +403 0 l +201 0 l +201 1493 l + +403 1063 m +403 504 l +657 504 l +751 504 824 528 875 577 c +926 626 952 695 952 784 c +952 873 926 942 875 990 c +824 1039 752 1063 657 1063 c +403 1063 l + +ce} _d +/germandbls{1290 0 186 -29 1196 1556 sc +186 1137 m +186 1270 226 1373 305 1446 c +385 1519 498 1556 643 1556 c +782 1556 887 1517 960 1440 c +1033 1363 1071 1249 1073 1100 c +972 1095 894 1073 838 1034 c +782 996 754 945 754 881 c +754 850 764 820 783 793 c +802 766 834 739 877 711 c +934 674 l +1045 603 1116 544 1148 497 c +1180 450 1196 393 1196 326 c +1196 211 1158 123 1083 62 c +1008 1 901 -29 760 -29 c +717 -29 673 -25 628 -16 c +583 -8 536 4 487 20 c +487 184 l +540 164 590 149 637 139 c +684 130 729 125 772 125 c +849 125 908 141 948 172 c +988 204 1008 250 1008 311 c +1008 353 998 388 978 416 c +959 444 915 479 848 520 c +756 575 l +692 614 645 656 616 701 c +587 746 573 799 573 860 c +573 945 601 1016 656 1073 c +712 1130 790 1169 891 1188 c +886 1257 861 1310 817 1347 c +774 1384 714 1403 639 1403 c +552 1403 486 1380 441 1333 c +396 1287 373 1220 373 1133 c +373 0 l +186 0 l +186 1137 l + +ce} _d +/agrave{1255 0 123 -29 1069 1638 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +449 1638 m +731 1264 l +578 1264 l +252 1638 l +449 1638 l + +ce} _d +/aacute{1255 0 123 -29 1069 1638 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +733 1638 m +932 1638 l +606 1262 l +453 1262 l +733 1638 l + +ce} _d +/acircumflex{1255 0 123 -29 1069 1638 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +520 1638 m +668 1638 l +913 1262 l +774 1262 l +594 1507 l +414 1262 l +275 1262 l +520 1638 l + +ce} _d +/atilde{1255 0 123 -29 1069 1591 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +590 1370 m +533 1425 l +518 1438 505 1448 494 1454 c +483 1461 474 1464 465 1464 c +440 1464 421 1452 409 1427 c +397 1403 390 1364 389 1309 c +264 1309 l +265 1399 283 1468 317 1517 c +351 1566 398 1591 459 1591 c +484 1591 508 1586 529 1577 c +550 1568 573 1552 598 1530 c +655 1475 l +670 1462 682 1452 693 1445 c +704 1439 714 1436 723 1436 c +748 1436 767 1448 779 1472 c +791 1497 798 1536 799 1591 c +924 1591 l +923 1501 905 1431 871 1382 c +837 1333 790 1309 729 1309 c +704 1309 680 1314 659 1323 c +638 1332 615 1348 590 1370 c + +ce} _d +/adieresis{1255 0 123 -29 1069 1552 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +688 1552 m +891 1552 l +891 1350 l +688 1350 l +688 1552 l + +297 1552 m +500 1552 l +500 1350 l +297 1350 l +297 1552 l + +ce} _d +/aring{1255 0 123 -29 1069 1798 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +746 1524 m +746 1566 731 1602 702 1631 c +673 1660 637 1675 594 1675 c +551 1675 514 1660 485 1631 c +456 1602 442 1567 442 1524 c +442 1481 456 1444 485 1415 c +514 1386 551 1372 594 1372 c +637 1372 673 1387 702 1416 c +731 1445 746 1481 746 1524 c + +868 1524 m +868 1447 841 1382 788 1329 c +735 1276 671 1249 594 1249 c +517 1249 452 1276 399 1329 c +346 1382 320 1447 320 1524 c +320 1601 346 1665 399 1718 c +452 1771 517 1798 594 1798 c +671 1798 735 1771 788 1718 c +841 1665 868 1601 868 1524 c + +ce} _d +/ae{2011 0 123 -29 1903 1147 sc +1718 660 m +1717 761 1689 841 1634 901 c +1579 961 1506 991 1415 991 c +1313 991 1231 962 1169 904 c +1108 846 1072 764 1063 659 c +1718 660 l + +995 963 m +1044 1023 1104 1069 1175 1100 c +1246 1131 1325 1147 1413 1147 c +1564 1147 1683 1098 1771 1001 c +1859 904 1903 773 1903 606 c +1903 516 l +1057 516 l +1065 389 1103 292 1171 225 c +1239 158 1334 125 1456 125 c +1525 125 1593 134 1660 151 c +1727 169 1793 196 1860 231 c +1860 57 l +1793 29 1725 8 1656 -7 c +1587 -22 1517 -29 1446 -29 c +1335 -29 1238 -9 1155 31 c +1072 72 1005 132 954 211 c +905 131 845 71 773 31 c +701 -9 617 -29 522 -29 c +396 -29 298 2 228 64 c +158 127 123 214 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +681 1147 763 1131 834 1099 c +905 1067 959 1022 995 963 c + +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +ce} _d +/ccedilla{1126 0 113 -395 999 1147 sc +999 1077 m +999 905 l +947 934 895 955 842 969 c +790 984 737 991 684 991 c +565 991 472 953 406 877 c +340 802 307 696 307 559 c +307 422 340 316 406 240 c +472 165 565 127 684 127 c +737 127 790 134 842 148 c +895 163 947 184 999 213 c +999 43 l +948 19 894 1 839 -11 c +784 -23 726 -29 664 -29 c +495 -29 361 24 262 130 c +163 236 113 379 113 559 c +113 742 163 885 263 990 c +364 1095 501 1147 676 1147 c +733 1147 788 1141 842 1129 c +896 1118 948 1100 999 1077 c + +739 0 m +776 -41 803 -79 821 -114 c +839 -149 848 -183 848 -215 c +848 -274 828 -319 788 -349 c +748 -380 689 -395 610 -395 c +579 -395 549 -393 520 -389 c +491 -385 463 -379 434 -371 c +434 -240 l +457 -251 480 -259 505 -264 c +530 -269 558 -272 589 -272 c +628 -272 658 -264 678 -248 c +698 -232 708 -209 708 -178 c +708 -158 701 -133 686 -104 c +672 -75 650 -41 620 0 c +739 0 l + +ce} _d +/egrave{1260 0 113 -29 1151 1638 sc +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +506 1638 m +788 1264 l +635 1264 l +309 1638 l +506 1638 l + +ce} _d +/eacute{1260 0 113 -29 1151 1638 sc +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +790 1638 m +989 1638 l +663 1262 l +510 1262 l +790 1638 l + +ce} _d +/ecircumflex{1260 0 113 -29 1151 1638 sc +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +577 1638 m +725 1638 l +970 1262 l +831 1262 l +651 1507 l +471 1262 l +332 1262 l +577 1638 l + +ce} _d +/edieresis{1260 0 113 -29 1151 1552 sc +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +745 1552 m +948 1552 l +948 1350 l +745 1350 l +745 1552 l + +354 1552 m +557 1552 l +557 1350 l +354 1350 l +354 1552 l + +ce} _d +/igrave{569 0 -57 0 422 1638 sc +140 1638 m +422 1264 l +269 1264 l +-57 1638 l +140 1638 l + +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +285 1147 m +285 1147 l + +ce} _d +/iacute{569 0 144 0 623 1638 sc +424 1638 m +623 1638 l +297 1262 l +144 1262 l +424 1638 l + +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +285 1147 m +285 1147 l + +ce} _d +/icircumflex{569 0 -34 0 604 1638 sc +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +285 1147 m +285 1147 l + +211 1638 m +359 1638 l +604 1262 l +465 1262 l +285 1507 l +105 1262 l +-34 1262 l +211 1638 l + +ce} _d +/idieresis{569 0 -12 0 582 1552 sc +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +285 1147 m +285 1147 l + +379 1552 m +582 1552 l +582 1350 l +379 1350 l +379 1552 l + +-12 1552 m +191 1552 l +191 1350 l +-12 1350 l +-12 1552 l + +ce} _d +/eth{1253 0 113 -29 1141 1556 sc +838 915 m +805 926 773 935 744 940 c +715 945 686 948 659 948 c +548 948 461 912 399 840 c +338 768 307 667 307 537 c +307 412 336 312 394 238 c +452 164 530 127 627 127 c +724 127 801 164 859 238 c +917 312 946 412 946 537 c +946 618 937 690 919 753 c +901 816 874 870 838 915 c + +901 1141 m +985 1046 1046 950 1084 854 c +1122 758 1141 652 1141 537 c +1141 367 1094 230 999 126 c +904 23 780 -29 627 -29 c +473 -29 349 23 254 126 c +160 230 113 367 113 537 c +113 704 159 839 251 942 c +343 1046 463 1098 610 1098 c +622 1098 637 1097 654 1095 c +671 1094 694 1091 722 1088 c +563 1268 l +244 1161 l +211 1260 l +492 1352 l +311 1556 l +539 1556 l +666 1411 l +999 1522 l +1032 1425 l +737 1327 l +901 1141 l + +ce} _d +/ntilde{1298 0 186 0 1124 1591 sc +1124 676 m +1124 0 l +940 0 l +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1027 c +1091 948 1124 831 1124 676 c + +660 1370 m +603 1425 l +588 1438 575 1448 564 1454 c +553 1461 544 1464 535 1464 c +510 1464 491 1452 479 1427 c +467 1403 460 1364 459 1309 c +334 1309 l +335 1399 353 1468 387 1517 c +421 1566 468 1591 529 1591 c +554 1591 578 1586 599 1577 c +620 1568 643 1552 668 1530 c +725 1475 l +740 1462 752 1452 763 1445 c +774 1439 784 1436 793 1436 c +818 1436 837 1448 849 1472 c +861 1497 868 1536 869 1591 c +994 1591 l +993 1501 975 1431 941 1382 c +907 1333 860 1309 799 1309 c +774 1309 750 1314 729 1323 c +708 1332 685 1348 660 1370 c + +ce} _d +/ograve{1253 0 113 -29 1141 1638 sc +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +482 1638 m +764 1264 l +611 1264 l +285 1638 l +482 1638 l + +ce} _d +/oacute{1253 0 113 -29 1141 1638 sc +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +766 1638 m +965 1638 l +639 1262 l +486 1262 l +766 1638 l + +ce} _d +/ocircumflex{1253 0 113 -29 1141 1638 sc +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +553 1638 m +701 1638 l +946 1262 l +807 1262 l +627 1507 l +447 1262 l +308 1262 l +553 1638 l + +ce} _d +/otilde{1253 0 113 -29 1141 1591 sc +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +623 1370 m +566 1425 l +551 1438 538 1448 527 1454 c +516 1461 507 1464 498 1464 c +473 1464 454 1452 442 1427 c +430 1403 423 1364 422 1309 c +297 1309 l +298 1399 316 1468 350 1517 c +384 1566 431 1591 492 1591 c +517 1591 541 1586 562 1577 c +583 1568 606 1552 631 1530 c +688 1475 l +703 1462 715 1452 726 1445 c +737 1439 747 1436 756 1436 c +781 1436 800 1448 812 1472 c +824 1497 831 1536 832 1591 c +957 1591 l +956 1501 938 1431 904 1382 c +870 1333 823 1309 762 1309 c +737 1309 713 1314 692 1323 c +671 1332 648 1348 623 1370 c + +ce} _d +/odieresis{1253 0 113 -29 1141 1552 sc +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +721 1552 m +924 1552 l +924 1350 l +721 1350 l +721 1552 l + +330 1552 m +533 1552 l +533 1350 l +330 1350 l +330 1552 l + +ce} _d +/divide{1716 0 217 150 1499 1135 sc +735 1135 m +981 1135 l +981 889 l +735 889 l +735 1135 l + +735 395 m +981 395 l +981 150 l +735 150 l +735 395 l + +217 727 m +1499 727 l +1499 557 l +217 557 l +217 727 l + +ce} _d +/oslash{1253 0 72 -94 1180 1212 sc +905 801 m +418 209 l +445 181 476 160 510 147 c +545 134 584 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 612 943 657 936 696 c +929 735 919 770 905 801 c + +834 909 m +806 936 775 957 740 970 c +706 984 668 991 627 991 c +526 991 448 952 391 873 c +335 795 307 686 307 545 c +307 497 310 455 316 418 c +323 381 333 348 346 317 c +834 909 l + +221 166 m +185 217 158 276 140 341 c +122 407 113 480 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c +689 1147 746 1138 799 1121 c +852 1104 901 1079 946 1044 c +1085 1212 l +1180 1133 l +1034 954 l +1069 903 1096 844 1114 778 c +1132 712 1141 639 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +563 -29 504 -20 450 -3 c +397 14 349 40 307 74 c +168 -94 l +72 -16 l +221 166 l + +ce} _d +/ugrave{1298 0 174 -29 1112 1638 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +490 1638 m +772 1264 l +619 1264 l +293 1638 l +490 1638 l + +ce} _d +/uacute{1298 0 174 -29 1112 1638 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +774 1638 m +973 1638 l +647 1262 l +494 1262 l +774 1638 l + +ce} _d +/ucircumflex{1298 0 174 -29 1112 1638 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +561 1638 m +709 1638 l +954 1262 l +815 1262 l +635 1507 l +455 1262 l +316 1262 l +561 1638 l + +ce} _d +/udieresis{1298 0 174 -29 1112 1552 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +729 1552 m +932 1552 l +932 1350 l +729 1350 l +729 1552 l + +338 1552 m +541 1552 l +541 1350 l +338 1350 l +338 1552 l + +ce} _d +/yacute{1212 0 61 -426 1151 1638 sc +659 -104 m +607 -237 556 -324 507 -365 c +458 -406 392 -426 309 -426 c +162 -426 l +162 -272 l +270 -272 l +321 -272 360 -260 388 -236 c +416 -212 447 -155 481 -66 c +514 18 l +61 1120 l +256 1120 l +606 244 l +956 1120 l +1151 1120 l +659 -104 l + +745 1638 m +944 1638 l +618 1262 l +465 1262 l +745 1638 l + +ce} _d +/thorn{1300 0 186 -426 1188 1556 sc +371 168 m +371 -426 l +186 -426 l +186 1556 l +371 1556 l +371 950 l +410 1017 458 1066 517 1098 c +576 1131 647 1147 729 1147 c +865 1147 975 1093 1060 985 c +1145 877 1188 735 1188 559 c +1188 383 1145 241 1060 133 c +975 25 865 -29 729 -29 c +647 -29 576 -13 517 19 c +458 52 410 101 371 168 c + +997 559 m +997 694 969 800 913 877 c +858 954 781 993 684 993 c +587 993 510 954 454 877 c +399 800 371 694 371 559 c +371 424 399 317 454 240 c +510 163 587 125 684 125 c +781 125 858 163 913 240 c +969 317 997 424 997 559 c + +ce} _d +/ydieresis{1212 0 61 -426 1151 1552 sc +659 -104 m +607 -237 556 -324 507 -365 c +458 -406 392 -426 309 -426 c +162 -426 l +162 -272 l +270 -272 l +321 -272 360 -260 388 -236 c +416 -212 447 -155 481 -66 c +514 18 l +61 1120 l +256 1120 l +606 244 l +956 1120 l +1151 1120 l +659 -104 l + +700 1552 m +903 1552 l +903 1350 l +700 1350 l +700 1552 l + +309 1552 m +512 1552 l +512 1350 l +309 1350 l +309 1552 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-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /DejaVuSans-1 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/Amacron /amacron /Abreve /abreve /Aogonek /aogonek /Cacute /cacute /Ccircumflex /ccircumflex /Cdotaccent /cdotaccent /Ccaron /ccaron /Dcaron /dcaron /Dcroat /dcroat /Emacron /emacron /Ebreve /ebreve /Edotaccent /edotaccent /Eogonek /eogonek /Ecaron /ecaron /Gcircumflex /gcircumflex /Gbreve /gbreve /Gdotaccent /gdotaccent /Gcommaaccent /gcommaaccent /Hcircumflex /hcircumflex /Hbar /hbar /Itilde /itilde /Imacron /imacron /Ibreve /ibreve /Iogonek /iogonek /Idotaccent /dotlessi /IJ /ij /Jcircumflex /jcircumflex /Kcommaaccent /kcommaaccent /kgreenlandic /Lacute /lacute /Lcommaaccent /lcommaaccent /Lcaron /lcaron /Ldot /ldot /Lslash /lslash /Nacute /nacute /Ncommaaccent /ncommaaccent /Ncaron /ncaron /napostrophe /Eng /eng /Omacron /omacron /Obreve /obreve /Ohungarumlaut /ohungarumlaut /OE /oe /Racute /racute /Rcommaaccent /rcommaaccent /Rcaron /rcaron /Sacute /sacute /Scircumflex /scircumflex /Scedilla /scedilla /Scaron /scaron /Tcommaaccent /tcommaaccent /Tcaron /tcaron /Tbar /tbar /Utilde /utilde /Umacron /umacron /Ubreve /ubreve /Uring /uring /Uhungarumlaut /uhungarumlaut /Uogonek /uogonek /Wcircumflex /wcircumflex /Ycircumflex /ycircumflex /Ydieresis /Zacute /zacute /Zdotaccent /zdotaccent /Zcaron /zcaron /longs /uni0180 /uni0181 /uni0182 /uni0183 /uni0184 /uni0185 /uni0186 /uni0187 /uni0188 /uni0189 /uni018A /uni018B /uni018C /uni018D /uni018E /uni018F /uni0190 /uni0191 /florin /uni0193 /uni0194 /uni0195 /uni0196 /uni0197 /uni0198 /uni0199 /uni019A /uni019B /uni019C /uni019D /uni019E /uni019F /Ohorn /ohorn /uni01A2 /uni01A3 /uni01A4 /uni01A5 /uni01A6 /uni01A7 /uni01A8 /uni01A9 /uni01AA /uni01AB /uni01AC /uni01AD /uni01AE /Uhorn /uhorn /uni01B1 /uni01B2 /uni01B3 /uni01B4 /uni01B5 /uni01B6 /uni01B7 /uni01B8 /uni01B9 /uni01BA /uni01BB /uni01BC /uni01BD /uni01BE /uni01BF /uni01C0 /uni01C1 /uni01C2 /uni01C3 /uni01C4 /uni01C5 /uni01C6 /uni01C7 /uni01C8 /uni01C9 /uni01CA /uni01CB /uni01CC /uni01CD /uni01CE /uni01CF /uni01D0 /uni01D1 /uni01D2 /uni01D3 /uni01D4 /uni01D5 /uni01D6 /uni01D7 /uni01D8 /uni01D9 /uni01DA /uni01DB /uni01DC /uni01DD /uni01DE /uni01DF /uni01E0 /uni01E1 /uni01E2 /uni01E3 /uni01E4 /uni01E5 /Gcaron /gcaron /uni01E8 /uni01E9 /uni01EA /uni01EB /uni01EC /uni01ED /uni01EE /uni01EF /uni01F0 /uni01F1 /uni01F2 /uni01F3 /uni01F4 /uni01F5 /uni01F6 /uni01F7 /uni01F8 /uni01F9 /Aringacute /aringacute /AEacute /aeacute /Oslashacute /oslashacute] def +/CharStrings 257 dict dup begin +/.notdef 0 def +/Amacron{1401 0 16 0 1384 1841 sc +401 1841 m +999 1841 l +999 1693 l +401 1693 l +401 1841 l + +700 1294 m +426 551 l +975 551 l +700 1294 l + +586 1493 m +815 1493 l +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +586 1493 l + +ce} _d +/amacron{1255 0 123 -29 1069 1526 sc +287 1526 m +885 1526 l +885 1378 l +287 1378 l +287 1526 l + +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +ce} _d +/Abreve{1401 0 16 0 1384 1938 sc +405 1938 m +523 1938 l +530 1888 550 1850 582 1825 c +615 1800 660 1788 718 1788 c +775 1788 820 1800 852 1825 c +884 1850 904 1887 913 1938 c +1031 1938 l +1024 1843 995 1771 942 1723 c +889 1675 815 1651 718 1651 c +621 1651 547 1675 494 1723 c +441 1771 412 1843 405 1938 c + +700 1294 m +426 551 l +975 551 l +700 1294 l + +586 1493 m +815 1493 l +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +586 1493 l + +ce} _d +/abreve{1255 0 123 -29 1069 1567 sc +278 1567 m +396 1567 l +403 1517 423 1479 455 1454 c +488 1429 533 1417 591 1417 c +648 1417 693 1429 725 1454 c +757 1479 777 1516 786 1567 c +904 1567 l +897 1472 868 1400 815 1352 c +762 1304 688 1280 591 1280 c +494 1280 420 1304 367 1352 c +314 1400 285 1472 278 1567 c + +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +ce} _d +/Aogonek{1401 0 16 -395 1445 1493 sc +700 1294 m +426 551 l +975 551 l +700 1294 l + +586 1493 m +815 1493 l +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +586 1493 l + +1180 0 m +1299 0 l +1269 -41 1247 -76 1232 -105 c +1218 -134 1211 -159 1211 -180 c +1211 -211 1220 -234 1238 -249 c +1257 -264 1284 -272 1320 -272 c +1341 -272 1362 -269 1383 -264 c +1404 -259 1424 -252 1445 -242 c +1445 -375 l +1420 -382 1396 -387 1373 -390 c +1350 -393 1329 -395 1309 -395 c +1228 -395 1168 -380 1129 -351 c +1091 -322 1072 -277 1072 -215 c +1072 -183 1081 -149 1098 -114 c +1116 -79 1143 -41 1180 0 c + +ce} _d +/aogonek{1255 0 123 -395 1152 1147 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +887 0 m +1006 0 l +976 -41 954 -76 939 -105 c +925 -134 918 -159 918 -180 c +918 -211 927 -234 945 -249 c +964 -264 991 -272 1027 -272 c +1048 -272 1069 -269 1090 -264 c +1111 -259 1131 -252 1152 -242 c +1152 -375 l +1127 -382 1103 -387 1080 -390 c +1057 -393 1036 -395 1016 -395 c +935 -395 875 -380 836 -351 c +798 -322 779 -277 779 -215 c +779 -183 788 -149 805 -114 c +823 -79 850 -41 887 0 c + +ce} _d +/Cacute{1430 0 115 -29 1319 1899 sc +1319 1378 m +1319 1165 l +1251 1228 1178 1276 1101 1307 c +1024 1338 943 1354 856 1354 c +685 1354 555 1302 464 1197 c +373 1093 328 942 328 745 c +328 548 373 398 464 293 c +555 189 685 137 856 137 c +943 137 1024 153 1101 184 c +1178 215 1251 263 1319 326 c +1319 115 l +1248 67 1173 31 1094 7 c +1015 -17 932 -29 844 -29 c +618 -29 440 40 310 178 c +180 317 115 506 115 745 c +115 985 180 1174 310 1312 c +440 1451 618 1520 844 1520 c +933 1520 1017 1508 1096 1484 c +1175 1461 1250 1425 1319 1378 c + +868 1899 m +1053 1899 l +825 1635 l +672 1635 l +868 1899 l + +ce} _d +/cacute{1126 0 113 -29 999 1638 sc +999 1077 m +999 905 l +947 934 895 955 842 969 c +790 984 737 991 684 991 c +565 991 472 953 406 877 c +340 802 307 696 307 559 c +307 422 340 316 406 240 c +472 165 565 127 684 127 c +737 127 790 134 842 148 c +895 163 947 184 999 213 c +999 43 l +948 19 894 1 839 -11 c +784 -23 726 -29 664 -29 c +495 -29 361 24 262 130 c +163 236 113 379 113 559 c +113 742 163 885 263 990 c +364 1095 501 1147 676 1147 c +733 1147 788 1141 842 1129 c +896 1118 948 1100 999 1077 c + +788 1638 m +987 1638 l +661 1262 l +508 1262 l +788 1638 l + +ce} _d +/Ccircumflex{1430 0 115 -29 1319 1901 sc +750 1901 m +938 1901 l +1149 1635 l +1010 1635 l +844 1813 l +678 1635 l +539 1635 l +750 1901 l + +1319 1378 m +1319 1165 l +1251 1228 1178 1276 1101 1307 c +1024 1338 943 1354 856 1354 c +685 1354 555 1302 464 1197 c +373 1093 328 942 328 745 c +328 548 373 398 464 293 c +555 189 685 137 856 137 c +943 137 1024 153 1101 184 c +1178 215 1251 263 1319 326 c +1319 115 l +1248 67 1173 31 1094 7 c +1015 -17 932 -29 844 -29 c +618 -29 440 40 310 178 c +180 317 115 506 115 745 c +115 985 180 1174 310 1312 c +440 1451 618 1520 844 1520 c +933 1520 1017 1508 1096 1484 c +1175 1461 1250 1425 1319 1378 c + +ce} _d +/ccircumflex{1126 0 113 -29 999 1638 sc +999 1077 m +999 905 l +947 934 895 955 842 969 c +790 984 737 991 684 991 c +565 991 472 953 406 877 c +340 802 307 696 307 559 c +307 422 340 316 406 240 c +472 165 565 127 684 127 c +737 127 790 134 842 148 c +895 163 947 184 999 213 c +999 43 l +948 19 894 1 839 -11 c +784 -23 726 -29 664 -29 c +495 -29 361 24 262 130 c +163 236 113 379 113 559 c +113 742 163 885 263 990 c +364 1095 501 1147 676 1147 c +733 1147 788 1141 842 1129 c +896 1118 948 1100 999 1077 c + +602 1638 m +750 1638 l +995 1262 l +856 1262 l +676 1507 l +496 1262 l +357 1262 l +602 1638 l + +ce} _d +/Cdotaccent{1430 0 115 -29 1319 1872 sc +742 1872 m +946 1872 l +946 1667 l +742 1667 l +742 1872 l + +1319 1378 m +1319 1165 l +1251 1228 1178 1276 1101 1307 c +1024 1338 943 1354 856 1354 c +685 1354 555 1302 464 1197 c +373 1093 328 942 328 745 c +328 548 373 398 464 293 c +555 189 685 137 856 137 c +943 137 1024 153 1101 184 c +1178 215 1251 263 1319 326 c +1319 115 l +1248 67 1173 31 1094 7 c +1015 -17 932 -29 844 -29 c +618 -29 440 40 310 178 c +180 317 115 506 115 745 c +115 985 180 1174 310 1312 c +440 1451 618 1520 844 1520 c +933 1520 1017 1508 1096 1484 c +1175 1461 1250 1425 1319 1378 c + +ce} _d +/cdotaccent{1126 0 113 -29 999 1556 sc +582 1556 m +766 1556 l +766 1323 l +582 1323 l +582 1556 l + +676 1147 m +676 1147 l + +999 1077 m +999 905 l +947 934 895 955 842 969 c +790 984 737 991 684 991 c +565 991 472 953 406 877 c +340 802 307 696 307 559 c +307 422 340 316 406 240 c +472 165 565 127 684 127 c +737 127 790 134 842 148 c +895 163 947 184 999 213 c +999 43 l +948 19 894 1 839 -11 c +784 -23 726 -29 664 -29 c +495 -29 361 24 262 130 c +163 236 113 379 113 559 c +113 742 163 885 263 990 c +364 1095 501 1147 676 1147 c +733 1147 788 1141 842 1129 c +896 1118 948 1100 999 1077 c + +ce} _d +/Ccaron{1430 0 115 -29 1319 1901 sc +1319 1378 m +1319 1165 l +1251 1228 1178 1276 1101 1307 c +1024 1338 943 1354 856 1354 c +685 1354 555 1302 464 1197 c +373 1093 328 942 328 745 c +328 548 373 398 464 293 c +555 189 685 137 856 137 c +943 137 1024 153 1101 184 c +1178 215 1251 263 1319 326 c +1319 115 l +1248 67 1173 31 1094 7 c +1015 -17 932 -29 844 -29 c +618 -29 440 40 310 178 c +180 317 115 506 115 745 c +115 985 180 1174 310 1312 c +440 1451 618 1520 844 1520 c +933 1520 1017 1508 1096 1484 c +1175 1461 1250 1425 1319 1378 c + +719 1635 m +508 1901 l +647 1901 l +813 1723 l +979 1901 l +1118 1901 l +907 1635 l +719 1635 l + +ce} _d +/ccaron{1126 0 113 -29 999 1638 sc +999 1077 m +999 905 l +947 934 895 955 842 969 c +790 984 737 991 684 991 c +565 991 472 953 406 877 c +340 802 307 696 307 559 c +307 422 340 316 406 240 c +472 165 565 127 684 127 c +737 127 790 134 842 148 c +895 163 947 184 999 213 c +999 43 l +948 19 894 1 839 -11 c +784 -23 726 -29 664 -29 c +495 -29 361 24 262 130 c +163 236 113 379 113 559 c +113 742 163 885 263 990 c +364 1095 501 1147 676 1147 c +733 1147 788 1141 842 1129 c +896 1118 948 1100 999 1077 c + +575 1262 m +330 1638 l +469 1638 l +649 1393 l +829 1638 l +968 1638 l +723 1262 l +575 1262 l + +ce} _d +/Dcaron{1577 0 201 0 1456 1901 sc +654 1635 m +443 1901 l +582 1901 l +748 1723 l +914 1901 l +1053 1901 l +842 1635 l +654 1635 l + +403 1327 m +403 166 l +647 166 l +853 166 1004 213 1099 306 c +1195 399 1243 547 1243 748 c +1243 948 1195 1094 1099 1187 c +1004 1280 853 1327 647 1327 c +403 1327 l + +201 1493 m +616 1493 l +905 1493 1118 1433 1253 1312 c +1388 1192 1456 1004 1456 748 c +1456 491 1388 302 1252 181 c +1116 60 904 0 616 0 c +201 0 l +201 1493 l + +ce} _d +/dcaron{1300 0 113 -29 1499 1556 sc +930 950 m +930 1556 l +1114 1556 l +1114 0 l +930 0 l +930 168 l +891 101 842 52 783 19 c +724 -13 654 -29 571 -29 c +436 -29 325 25 240 133 c +155 241 113 383 113 559 c +113 735 155 877 240 985 c +325 1093 436 1147 571 1147 c +654 1147 724 1131 783 1098 c +842 1066 891 1017 930 950 c + +303 559 m +303 424 331 317 386 240 c +442 163 519 125 616 125 c +713 125 790 163 846 240 c +902 317 930 424 930 559 c +930 694 902 800 846 877 c +790 954 713 993 616 993 c +519 993 442 954 386 877 c +331 800 303 694 303 559 c + +1300 1554 m +1499 1554 l +1382 1178 l +1229 1178 l +1300 1554 l + +ce} _d +/Dcroat{1587 0 10 0 1466 1493 sc +211 1493 m +627 1493 l +916 1493 1128 1433 1263 1312 c +1398 1192 1466 1004 1466 748 c +1466 491 1398 302 1262 181 c +1127 60 915 0 627 0 c +211 0 l +211 700 l +10 700 l +10 844 l +211 844 l +211 1493 l + +414 1327 m +414 844 l +750 844 l +750 700 l +414 700 l +414 166 l +657 166 l +863 166 1014 213 1109 306 c +1205 399 1253 547 1253 748 c +1253 948 1205 1094 1109 1187 c +1014 1280 863 1327 657 1327 c +414 1327 l + +ce} _d +/dcroat{1300 0 113 -29 1268 1556 sc +930 950 m +930 1284 l +604 1284 l +604 1409 l +930 1409 l +930 1556 l +1114 1556 l +1114 1409 l +1268 1409 l +1268 1284 l +1114 1284 l +1114 0 l +930 0 l +930 168 l +891 101 842 52 783 19 c +724 -13 654 -29 571 -29 c +436 -29 325 25 240 133 c +155 241 113 383 113 559 c +113 735 155 877 240 985 c +325 1093 436 1147 571 1147 c +654 1147 724 1131 783 1098 c +842 1066 891 1017 930 950 c + +303 559 m +303 424 331 317 386 240 c +442 163 519 125 616 125 c +713 125 790 163 846 240 c +902 317 930 424 930 559 c +930 694 902 800 846 877 c +790 954 713 993 616 993 c +519 993 442 954 386 877 c +331 800 303 694 303 559 c + +ce} _d +/Emacron{1294 0 201 0 1163 1843 sc +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +374 1843 m +972 1843 l +972 1695 l +374 1695 l +374 1843 l + +ce} _d +/emacron{1260 0 113 -29 1151 1526 sc +363 1526 m +961 1526 l +961 1378 l +363 1378 l +363 1526 l + +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +ce} _d +/Ebreve{1294 0 201 0 1163 1901 sc +360 1901 m +478 1901 l +487 1865 507 1837 540 1818 c +573 1799 618 1790 673 1790 c +728 1790 771 1799 803 1817 c +836 1836 857 1864 868 1901 c +986 1901 l +979 1822 949 1761 896 1720 c +843 1679 768 1659 673 1659 c +577 1659 502 1679 449 1720 c +396 1761 367 1821 360 1901 c + +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +ce} _d +/ebreve{1260 0 113 -29 1151 1608 sc +349 1608 m +467 1608 l +474 1558 494 1520 526 1495 c +559 1470 604 1458 662 1458 c +719 1458 764 1470 796 1495 c +828 1520 848 1557 857 1608 c +975 1608 l +968 1513 939 1441 886 1393 c +833 1345 759 1321 662 1321 c +565 1321 491 1345 438 1393 c +385 1441 356 1513 349 1608 c + +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +ce} _d +/Edotaccent{1294 0 201 0 1163 1872 sc +568 1872 m +772 1872 l +772 1667 l +568 1667 l +568 1872 l + +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +ce} _d +/edotaccent{1260 0 113 -29 1151 1556 sc +568 1556 m +752 1556 l +752 1323 l +568 1323 l +568 1556 l + +662 1147 m +662 1147 l + +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +ce} _d +/Eogonek{1294 0 201 -395 1165 1493 sc +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +900 0 m +1019 0 l +989 -41 967 -76 952 -105 c +938 -134 931 -159 931 -180 c +931 -211 940 -234 958 -249 c +977 -264 1004 -272 1040 -272 c +1061 -272 1082 -269 1103 -264 c +1124 -259 1144 -252 1165 -242 c +1165 -375 l +1140 -382 1116 -387 1093 -390 c +1070 -393 1049 -395 1029 -395 c +948 -395 888 -380 849 -351 c +811 -322 792 -277 792 -215 c +792 -183 801 -149 818 -114 c +836 -79 863 -41 900 0 c + +ce} _d +/eogonek{1260 0 113 -395 1151 1147 sc +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +816 0 m +935 0 l +905 -41 883 -76 868 -105 c +854 -134 847 -159 847 -180 c +847 -211 856 -234 874 -249 c +893 -264 920 -272 956 -272 c +977 -272 998 -269 1019 -264 c +1040 -259 1060 -252 1081 -242 c +1081 -375 l +1056 -382 1032 -387 1009 -390 c +986 -393 965 -395 945 -395 c +864 -395 804 -380 765 -351 c +727 -322 708 -277 708 -215 c +708 -183 717 -149 734 -114 c +752 -79 779 -41 816 0 c + +ce} _d +/Ecaron{1294 0 201 0 1163 1895 sc +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +584 1629 m +373 1895 l +512 1895 l +678 1717 l +844 1895 l +983 1895 l +772 1629 l +584 1629 l + +ce} _d +/ecaron{1260 0 113 -29 1151 1633 sc +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +586 1257 m +341 1633 l +480 1633 l +660 1388 l +840 1633 l +979 1633 l +734 1257 l +586 1257 l + +ce} _d +/Gcircumflex{1587 0 115 -29 1419 1901 sc +766 1901 m +954 1901 l +1165 1635 l +1026 1635 l +860 1813 l +694 1635 l +555 1635 l +766 1901 l + +1219 213 m +1219 614 l +889 614 l +889 780 l +1419 780 l +1419 139 l +1341 84 1255 42 1161 13 c +1067 -15 967 -29 860 -29 c +627 -29 444 39 312 175 c +181 312 115 502 115 745 c +115 989 181 1179 312 1315 c +444 1452 627 1520 860 1520 c +957 1520 1050 1508 1137 1484 c +1225 1460 1306 1425 1380 1378 c +1380 1163 l +1305 1226 1226 1274 1142 1306 c +1058 1338 970 1354 877 1354 c +694 1354 557 1303 465 1201 c +374 1099 328 947 328 745 c +328 544 374 392 465 290 c +557 188 694 137 877 137 c +948 137 1012 143 1068 155 c +1124 168 1174 187 1219 213 c + +ce} _d +/gcircumflex{1300 0 113 -426 1114 1638 sc +542 1638 m +690 1638 l +935 1262 l +796 1262 l +616 1507 l +436 1262 l +297 1262 l +542 1638 l + +930 573 m +930 706 902 810 847 883 c +792 956 715 993 616 993 c +517 993 440 956 385 883 c +330 810 303 706 303 573 c +303 440 330 337 385 264 c +440 191 517 154 616 154 c +715 154 792 191 847 264 c +902 337 930 440 930 573 c + +1114 139 m +1114 -52 1072 -193 987 -286 c +902 -379 773 -426 598 -426 c +533 -426 472 -421 415 -411 c +358 -402 302 -387 248 -367 c +248 -188 l +302 -217 355 -239 408 -253 c +461 -267 514 -274 569 -274 c +690 -274 780 -242 840 -179 c +900 -116 930 -21 930 106 c +930 197 l +892 131 843 82 784 49 c +725 16 654 0 571 0 c +434 0 323 52 239 157 c +155 262 113 400 113 573 c +113 746 155 885 239 990 c +323 1095 434 1147 571 1147 c +654 1147 725 1131 784 1098 c +843 1065 892 1016 930 950 c +930 1120 l +1114 1120 l +1114 139 l + +ce} _d +/Gbreve{1587 0 115 -29 1419 1901 sc +1219 213 m +1219 614 l +889 614 l +889 780 l +1419 780 l +1419 139 l +1341 84 1255 42 1161 13 c +1067 -15 967 -29 860 -29 c +627 -29 444 39 312 175 c +181 312 115 502 115 745 c +115 989 181 1179 312 1315 c +444 1452 627 1520 860 1520 c +957 1520 1050 1508 1137 1484 c +1225 1460 1306 1425 1380 1378 c +1380 1163 l +1305 1226 1226 1274 1142 1306 c +1058 1338 970 1354 877 1354 c +694 1354 557 1303 465 1201 c +374 1099 328 947 328 745 c +328 544 374 392 465 290 c +557 188 694 137 877 137 c +948 137 1012 143 1068 155 c +1124 168 1174 187 1219 213 c + +482 1901 m +600 1901 l +609 1865 629 1837 662 1818 c +695 1799 740 1790 795 1790 c +850 1790 893 1799 925 1817 c +958 1836 979 1864 990 1901 c +1108 1901 l +1101 1822 1071 1761 1018 1720 c +965 1679 890 1659 795 1659 c +699 1659 624 1679 571 1720 c +518 1761 489 1821 482 1901 c + +ce} _d +/gbreve{1300 0 113 -426 1114 1608 sc +930 573 m +930 706 902 810 847 883 c +792 956 715 993 616 993 c +517 993 440 956 385 883 c +330 810 303 706 303 573 c +303 440 330 337 385 264 c +440 191 517 154 616 154 c +715 154 792 191 847 264 c +902 337 930 440 930 573 c + +1114 139 m +1114 -52 1072 -193 987 -286 c +902 -379 773 -426 598 -426 c +533 -426 472 -421 415 -411 c +358 -402 302 -387 248 -367 c +248 -188 l +302 -217 355 -239 408 -253 c +461 -267 514 -274 569 -274 c +690 -274 780 -242 840 -179 c +900 -116 930 -21 930 106 c +930 197 l +892 131 843 82 784 49 c +725 16 654 0 571 0 c +434 0 323 52 239 157 c +155 262 113 400 113 573 c +113 746 155 885 239 990 c +323 1095 434 1147 571 1147 c +654 1147 725 1131 784 1098 c +843 1065 892 1016 930 950 c +930 1120 l +1114 1120 l +1114 139 l + +338 1608 m +456 1608 l +463 1558 483 1520 515 1495 c +548 1470 593 1458 651 1458 c +708 1458 753 1470 785 1495 c +817 1520 837 1557 846 1608 c +964 1608 l +957 1513 928 1441 875 1393 c +822 1345 748 1321 651 1321 c +554 1321 480 1345 427 1393 c +374 1441 345 1513 338 1608 c + +ce} _d +/Gdotaccent{1587 0 115 -29 1419 1872 sc +758 1872 m +962 1872 l +962 1667 l +758 1667 l +758 1872 l + +1219 213 m +1219 614 l +889 614 l +889 780 l +1419 780 l +1419 139 l +1341 84 1255 42 1161 13 c +1067 -15 967 -29 860 -29 c +627 -29 444 39 312 175 c +181 312 115 502 115 745 c +115 989 181 1179 312 1315 c +444 1452 627 1520 860 1520 c +957 1520 1050 1508 1137 1484 c +1225 1460 1306 1425 1380 1378 c +1380 1163 l +1305 1226 1226 1274 1142 1306 c +1058 1338 970 1354 877 1354 c +694 1354 557 1303 465 1201 c +374 1099 328 947 328 745 c +328 544 374 392 465 290 c +557 188 694 137 877 137 c +948 137 1012 143 1068 155 c +1124 168 1174 187 1219 213 c + +ce} _d +/gdotaccent{1300 0 113 -426 1114 1556 sc +524 1556 m +708 1556 l +708 1323 l +524 1323 l +524 1556 l + +618 1147 m +618 1147 l + +930 573 m +930 706 902 810 847 883 c +792 956 715 993 616 993 c +517 993 440 956 385 883 c +330 810 303 706 303 573 c +303 440 330 337 385 264 c +440 191 517 154 616 154 c +715 154 792 191 847 264 c +902 337 930 440 930 573 c + +1114 139 m +1114 -52 1072 -193 987 -286 c +902 -379 773 -426 598 -426 c +533 -426 472 -421 415 -411 c +358 -402 302 -387 248 -367 c +248 -188 l +302 -217 355 -239 408 -253 c +461 -267 514 -274 569 -274 c +690 -274 780 -242 840 -179 c +900 -116 930 -21 930 106 c +930 197 l +892 131 843 82 784 49 c +725 16 654 0 571 0 c +434 0 323 52 239 157 c +155 262 113 400 113 573 c +113 746 155 885 239 990 c +323 1095 434 1147 571 1147 c +654 1147 725 1131 784 1098 c +843 1065 892 1016 930 950 c +930 1120 l +1114 1120 l +1114 139 l + +ce} _d +/Gcommaaccent{1587 0 115 -511 1419 1520 sc +794 -191 m +1005 -191 l +841 -511 l +712 -511 l +794 -191 l + +1219 213 m +1219 614 l +889 614 l +889 780 l +1419 780 l +1419 139 l +1341 84 1255 42 1161 13 c +1067 -15 967 -29 860 -29 c +627 -29 444 39 312 175 c +181 312 115 502 115 745 c +115 989 181 1179 312 1315 c +444 1452 627 1520 860 1520 c +957 1520 1050 1508 1137 1484 c +1225 1460 1306 1425 1380 1378 c +1380 1163 l +1305 1226 1226 1274 1142 1306 c +1058 1338 970 1354 877 1354 c +694 1354 557 1303 465 1201 c +374 1099 328 947 328 745 c +328 544 374 392 465 290 c +557 188 694 137 877 137 c +948 137 1012 143 1068 155 c +1124 168 1174 187 1219 213 c + +ce} _d +/gcommaaccent{1300 0 113 -426 1114 1588 sc +722 1269 m +511 1269 l +675 1588 l +804 1588 l +722 1269 l + +930 573 m +930 706 902 810 847 883 c +792 956 715 993 616 993 c +517 993 440 956 385 883 c +330 810 303 706 303 573 c +303 440 330 337 385 264 c +440 191 517 154 616 154 c +715 154 792 191 847 264 c +902 337 930 440 930 573 c + +1114 139 m +1114 -52 1072 -193 987 -286 c +902 -379 773 -426 598 -426 c +533 -426 472 -421 415 -411 c +358 -402 302 -387 248 -367 c +248 -188 l +302 -217 355 -239 408 -253 c +461 -267 514 -274 569 -274 c +690 -274 780 -242 840 -179 c +900 -116 930 -21 930 106 c +930 197 l +892 131 843 82 784 49 c +725 16 654 0 571 0 c +434 0 323 52 239 157 c +155 262 113 400 113 573 c +113 746 155 885 239 990 c +323 1095 434 1147 571 1147 c +654 1147 725 1131 784 1098 c +843 1065 892 1016 930 950 c +930 1120 l +1114 1120 l +1114 139 l + +ce} _d +/Hcircumflex{1540 0 201 0 1339 1901 sc +676 1901 m +864 1901 l +1075 1635 l +936 1635 l +770 1813 l +604 1635 l +465 1635 l +676 1901 l + +201 1493 m +403 1493 l +403 881 l +1137 881 l +1137 1493 l +1339 1493 l +1339 0 l +1137 0 l +1137 711 l +403 711 l +403 0 l +201 0 l +201 1493 l + +ce} _d +/hcircumflex{1298 0 -27 0 1124 1901 sc +184 1901 m +372 1901 l +583 1635 l +444 1635 l +278 1813 l +112 1635 l +-27 1635 l +184 1901 l + +1124 676 m +1124 0 l +940 0 l +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1556 l +371 1556 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1027 c +1091 948 1124 831 1124 676 c + +ce} _d +/Hbar{1876 0 201 0 1675 1493 sc +369 1493 m +571 1493 l +571 1269 l +1305 1269 l +1305 1493 l +1507 1493 l +1507 1269 l +1675 1269 l +1675 1105 l +1507 1105 l +1507 0 l +1305 0 l +1305 711 l +571 711 l +571 0 l +369 0 l +369 1105 l +201 1105 l +201 1269 l +369 1269 l +369 1493 l + +571 1105 m +571 881 l +1305 881 l +1305 1105 l +571 1105 l + +ce} _d +/hbar{1423 0 120 0 1183 1556 sc +1183 676 m +1183 0 l +999 0 l +999 670 l +999 776 978 855 937 908 c +896 961 834 987 751 987 c +652 987 573 955 516 892 c +459 829 430 742 430 633 c +430 0 l +245 0 l +245 1270 l +120 1270 l +120 1434 l +245 1434 l +245 1556 l +430 1556 l +430 1434 l +782 1434 l +782 1270 l +430 1270 l +430 946 l +474 1013 526 1064 585 1097 c +645 1130 714 1147 792 1147 c +921 1147 1018 1107 1084 1027 c +1150 948 1183 831 1183 676 c + +ce} _d +/Itilde{604 0 -28 0 632 1886 sc +298 1710 m +241 1743 l +224 1752 211 1759 200 1762 c +190 1766 181 1768 173 1768 c +149 1768 130 1760 117 1743 c +104 1726 97 1703 97 1673 c +97 1667 l +-28 1667 l +-28 1734 -11 1788 23 1827 c +58 1866 104 1886 161 1886 c +185 1886 207 1883 227 1878 c +248 1873 274 1861 306 1843 c +363 1813 l +378 1804 392 1798 403 1794 c +414 1790 425 1788 435 1788 c +456 1788 474 1796 487 1813 c +500 1830 507 1853 507 1880 c +507 1886 l +632 1886 l +631 1819 613 1766 578 1726 c +544 1687 499 1667 443 1667 c +420 1667 399 1670 379 1675 c +360 1680 333 1692 298 1710 c + +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +ce} _d +/itilde{569 0 -45 0 615 1591 sc +281 1370 m +224 1425 l +209 1438 196 1448 185 1454 c +174 1461 165 1464 156 1464 c +131 1464 112 1452 100 1427 c +88 1403 81 1364 80 1309 c +-45 1309 l +-44 1399 -26 1468 8 1517 c +42 1566 89 1591 150 1591 c +175 1591 199 1586 220 1577 c +241 1568 264 1552 289 1530 c +346 1475 l +361 1462 373 1452 384 1445 c +395 1439 405 1436 414 1436 c +439 1436 458 1448 470 1472 c +482 1497 489 1536 490 1591 c +615 1591 l +614 1501 596 1431 562 1382 c +528 1333 481 1309 420 1309 c +395 1309 371 1314 350 1323 c +329 1332 306 1348 281 1370 c + +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +285 1147 m +285 1147 l + +ce} _d +/Imacron{604 0 3 0 601 1841 sc +3 1841 m +601 1841 l +601 1693 l +3 1693 l +3 1841 l + +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +ce} _d +/imacron{569 0 -14 0 584 1525 sc +-14 1525 m +584 1525 l +584 1377 l +-14 1377 l +-14 1525 l + +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +285 1147 m +285 1147 l + +ce} _d +/Ibreve{604 0 -11 0 615 1901 sc +-11 1901 m +107 1901 l +116 1865 136 1837 169 1818 c +202 1799 247 1790 302 1790 c +357 1790 400 1799 432 1817 c +465 1836 486 1864 497 1901 c +615 1901 l +608 1822 578 1761 525 1720 c +472 1679 397 1659 302 1659 c +206 1659 131 1679 78 1720 c +25 1761 -4 1821 -11 1901 c + +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +ce} _d +/ibreve{569 0 -28 0 598 1608 sc +-28 1608 m +90 1608 l +97 1558 117 1520 149 1495 c +182 1470 227 1458 285 1458 c +342 1458 387 1470 419 1495 c +451 1520 471 1557 480 1608 c +598 1608 l +591 1513 562 1441 509 1393 c +456 1345 382 1321 285 1321 c +188 1321 114 1345 61 1393 c +8 1441 -21 1513 -28 1608 c + +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +285 1147 m +285 1147 l + +ce} _d +/Iogonek{604 0 176 -395 549 1493 sc +284 0 m +403 0 l +373 -41 351 -76 336 -105 c +322 -134 315 -159 315 -180 c +315 -211 324 -234 342 -249 c +361 -264 388 -272 424 -272 c +445 -272 466 -269 487 -264 c +508 -259 528 -252 549 -242 c +549 -375 l +524 -382 500 -387 477 -390 c +454 -393 433 -395 413 -395 c +332 -395 272 -380 233 -351 c +195 -322 176 -277 176 -215 c +176 -183 185 -149 202 -114 c +220 -79 247 -41 284 0 c + +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +ce} _d +/iogonek{569 0 150 -395 523 1556 sc +258 0 m +377 0 l +347 -41 325 -76 310 -105 c +296 -134 289 -159 289 -180 c +289 -211 298 -234 316 -249 c +335 -264 362 -272 398 -272 c +419 -272 440 -269 461 -264 c +482 -259 502 -252 523 -242 c +523 -375 l +498 -382 474 -387 451 -390 c +428 -393 407 -395 387 -395 c +306 -395 246 -380 207 -351 c +169 -322 150 -277 150 -215 c +150 -183 159 -149 176 -114 c +194 -79 221 -41 258 0 c + +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +193 1556 m +377 1556 l +377 1323 l +193 1323 l +193 1556 l + +ce} _d +/Idotaccent{604 0 201 0 405 1872 sc +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +201 1872 m +405 1872 l +405 1667 l +201 1667 l +201 1872 l + +ce} _d +/dotlessi{569 0 193 0 377 1147 sc +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +285 1147 m +285 1147 l + +ce} _d +/IJ{1208 0 201 -410 1007 1493 sc +805 1493 m +1007 1493 l +1007 104 l +1007 -76 973 -207 904 -288 c +836 -369 726 -410 575 -410 c +498 -410 l +498 -240 l +561 -240 l +650 -240 713 -215 750 -165 c +787 -115 805 -25 805 104 c +805 1493 l + +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +ce} _d +/ij{1138 0 193 -426 945 1556 sc +761 1120 m +945 1120 l +945 -20 l +945 -163 918 -266 863 -330 c +809 -394 722 -426 601 -426 c +531 -426 l +531 -270 l +580 -270 l +650 -270 698 -254 723 -221 c +748 -189 761 -122 761 -20 c +761 1120 l + +761 1556 m +945 1556 l +945 1323 l +761 1323 l +761 1556 l + +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +193 1556 m +377 1556 l +377 1323 l +193 1323 l +193 1556 l + +ce} _d +/Jcircumflex{604 0 -106 -410 607 1901 sc +208 1901 m +396 1901 l +607 1635 l +468 1635 l +302 1813 l +136 1635 l +-3 1635 l +208 1901 l + +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 +/jcircumflex{569 0 -37 -426 604 1638 sc +211 1638 m +359 1638 l +604 1262 l +465 1262 l +285 1507 l +105 1262 l +-34 1262 l +211 1638 l + +193 1120 m +377 1120 l +377 -20 l +377 -163 350 -266 295 -330 c +241 -394 154 -426 33 -426 c +-37 -426 l +-37 -270 l +12 -270 l +82 -270 130 -254 155 -221 c +180 -189 193 -122 193 -20 c +193 1120 l + +ce} _d +/Kcommaaccent{1343 0 201 -482 1386 1493 sc +727 -162 m +938 -162 l +774 -482 l +645 -482 l +727 -162 l + +201 1493 m +403 1493 l +403 862 l +1073 1493 l +1333 1493 l +592 797 l +1386 0 l +1120 0 l +403 719 l +403 0 l +201 0 l +201 1493 l + +ce} _d +/kcommaaccent{1186 0 186 -482 1180 1556 sc +616 -162 m +827 -162 l +663 -482 l +534 -482 l +616 -162 l + +186 1556 m +371 1556 l +371 637 l +920 1120 l +1155 1120 l +561 596 l +1180 0 l +940 0 l +371 547 l +371 0 l +186 0 l +186 1556 l + +ce} _d +/kgreenlandic{1186 0 186 0 1180 1120 sc +186 1120 m +371 1120 l +371 635 l +920 1120 l +1155 1120 l +561 594 l +1180 0 l +940 0 l +371 545 l +371 0 l +186 0 l +186 1120 l + +ce} _d +/Lacute{1141 0 201 0 1130 1900 sc +421 1900 m +606 1900 l +378 1636 l +225 1636 l +421 1900 l + +201 1493 m +403 1493 l +403 170 l +1130 170 l +1130 0 l +201 0 l +201 1493 l + +ce} _d +/lacute{569 0 193 0 586 1900 sc +401 1900 m +586 1900 l +358 1636 l +205 1636 l +401 1900 l + +193 1556 m +377 1556 l +377 0 l +193 0 l +193 1556 l + +ce} _d +/Lcommaaccent{1141 0 201 -482 1130 1493 sc +599 -162 m +810 -162 l +646 -482 l +517 -482 l +599 -162 l + +201 1493 m +403 1493 l +403 170 l +1130 170 l +1130 0 l +201 0 l +201 1493 l + +ce} _d +/lcommaaccent{569 0 136 -482 429 1556 sc +218 -162 m +429 -162 l +265 -482 l +136 -482 l +218 -162 l + +193 1556 m +377 1556 l +377 0 l +193 0 l +193 1556 l + +ce} _d +/Lcaron{1141 0 201 0 1130 1493 sc +671 1493 m +870 1493 l +753 1117 l +600 1117 l +671 1493 l + +201 1493 m +403 1493 l +403 170 l +1130 170 l +1130 0 l +201 0 l +201 1493 l + +ce} _d +/lcaron{768 0 193 0 768 1556 sc +569 1556 m +768 1556 l +651 1180 l +498 1180 l +569 1556 l + +193 1556 m +377 1556 l +377 0 l +193 0 l +193 1556 l + +ce} _d +/Ldot{1141 0 201 0 1130 1493 sc +780 957 m +991 957 l +991 703 l +780 703 l +780 957 l + +201 1493 m +403 1493 l +403 170 l +1130 170 l +1130 0 l +201 0 l +201 1493 l + +ce} _d +/ldot{700 0 193 0 644 1556 sc +433 953 m +644 953 l +644 699 l +433 699 l +433 953 l + +193 1556 m +377 1556 l +377 0 l +193 0 l +193 1556 l + +ce} _d +/Lslash{1151 0 -14 0 1141 1493 sc +211 1493 m +414 1493 l +414 877 l +727 1096 l +807 985 l +414 711 l +414 170 l +1141 170 l +1141 0 l +211 0 l +211 571 l +63 465 l +-14 575 l +211 733 l +211 1493 l + +ce} _d +/lslash{582 0 2 0 584 1556 sc +199 1556 m +383 1556 l +383 954 l +508 1044 l +584 938 l +383 797 l +383 0 l +199 0 l +199 666 l +76 578 l +2 684 l +199 825 l +199 1556 l + +ce} _d +/Nacute{1532 0 201 0 1331 1900 sc +764 1900 m +949 1900 l +721 1636 l +568 1636 l +764 1900 l + +201 1493 m +473 1493 l +1135 244 l +1135 1493 l +1331 1493 l +1331 0 l +1059 0 l +397 1249 l +397 0 l +201 0 l +201 1493 l + +ce} _d +/nacute{1298 0 186 0 1124 1645 sc +717 1645 m +916 1645 l +590 1269 l +437 1269 l +717 1645 l + +1124 676 m +1124 0 l +940 0 l +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1027 c +1091 948 1124 831 1124 676 c + +ce} _d +/Ncommaaccent{1532 0 201 -482 1331 1493 sc +700 -162 m +911 -162 l +747 -482 l +618 -482 l +700 -162 l + +201 1493 m +473 1493 l +1135 244 l +1135 1493 l +1331 1493 l +1331 0 l +1059 0 l +397 1249 l +397 0 l +201 0 l +201 1493 l + +ce} _d +/ncommaaccent{1298 0 186 -482 1124 1147 sc +588 -162 m +799 -162 l +635 -482 l +506 -482 l +588 -162 l + +1124 676 m +1124 0 l +940 0 l +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1027 c +1091 948 1124 831 1124 676 c + +ce} _d +/Ncaron{1532 0 201 0 1331 1887 sc +201 1493 m +473 1493 l +1135 244 l +1135 1493 l +1331 1493 l +1331 0 l +1059 0 l +397 1249 l +397 0 l +201 0 l +201 1493 l + +663 1621 m +452 1887 l +591 1887 l +757 1709 l +923 1887 l +1062 1887 l +851 1621 l +663 1621 l + +ce} _d +/ncaron{1298 0 186 0 1124 1638 sc +1124 676 m +1124 0 l +940 0 l +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1027 c +1091 948 1124 831 1124 676 c + +579 1262 m +334 1638 l +473 1638 l +653 1393 l +833 1638 l +972 1638 l +727 1262 l +579 1262 l + +ce} _d +/napostrophe{1666 0 205 0 1465 1493 sc +1465 676 m +1465 0 l +1281 0 l +1281 670 l +1281 776 1260 855 1219 908 c +1178 961 1116 987 1033 987 c +934 987 855 955 798 892 c +741 829 712 742 712 633 c +712 0 l +527 0 l +527 1120 l +712 1120 l +712 946 l +756 1013 808 1064 867 1097 c +927 1130 996 1147 1074 1147 c +1203 1147 1300 1107 1366 1027 c +1432 948 1465 831 1465 676 c + +287 1493 m +498 1493 l +498 1341 l +334 1022 l +205 1022 l +287 1341 l +287 1493 l + +ce} _d +/Eng{1532 0 201 -426 1305 1520 sc +1104 895 m +1104 1180 1002 1323 797 1323 c +678 1323 582 1280 510 1195 c +439 1110 403 994 403 846 c +403 0 l +201 0 l +201 1493 l +403 1493 l +403 1252 l +455 1341 516 1408 586 1453 c +657 1498 743 1520 845 1520 c +996 1520 1111 1467 1188 1360 c +1266 1254 1305 1098 1305 893 c +1305 -20 l +1305 -162 1278 -265 1224 -330 c +1169 -394 1082 -426 961 -426 c +874 -426 l +874 -270 l +923 -270 l +991 -270 1038 -255 1064 -225 c +1091 -195 1104 -127 1104 -20 c +1104 895 l + +ce} _d +/eng{1298 0 186 -426 1124 1147 sc +1124 676 m +1124 -20 l +1124 -163 1097 -266 1042 -330 c +988 -394 901 -426 780 -426 c +526 -426 l +526 -270 l +759 -270 l +829 -270 877 -254 902 -222 c +927 -189 940 -122 940 -20 c +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1028 c +1091 948 1124 831 1124 676 c + +ce} _d +/Omacron{1612 0 115 -29 1497 1841 sc +508 1841 m +1106 1841 l +1106 1693 l +508 1693 l +508 1841 l + +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +ce} _d +/omacron{1253 0 113 -29 1141 1525 sc +328 1525 m +926 1525 l +926 1377 l +328 1377 l +328 1525 l + +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +ce} _d +/Obreve{1612 0 115 -29 1497 1901 sc +494 1901 m +612 1901 l +621 1865 641 1837 674 1818 c +707 1799 752 1790 807 1790 c +862 1790 905 1799 937 1817 c +970 1836 991 1864 1002 1901 c +1120 1901 l +1113 1822 1083 1761 1030 1720 c +977 1679 902 1659 807 1659 c +711 1659 636 1679 583 1720 c +530 1761 501 1821 494 1901 c + +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +ce} _d +/obreve{1253 0 113 -29 1141 1608 sc +314 1608 m +432 1608 l +439 1558 459 1520 491 1495 c +524 1470 569 1458 627 1458 c +684 1458 729 1470 761 1495 c +793 1520 813 1557 822 1608 c +940 1608 l +933 1513 904 1441 851 1393 c +798 1345 724 1321 627 1321 c +530 1321 456 1345 403 1393 c +350 1441 321 1513 314 1608 c + +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +ce} _d +/Ohungarumlaut{1612 0 115 -29 1497 1899 sc +1056 1899 m +1241 1899 l +1013 1635 l +860 1635 l +1056 1899 l + +721 1899 m +906 1899 l +678 1635 l +525 1635 l +721 1899 l + +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +ce} _d +/ohungarumlaut{1253 0 113 -29 1141 1638 sc +924 1638 m +1102 1638 l +854 1262 l +719 1262 l +924 1638 l + +590 1638 m +760 1638 l +537 1262 l +400 1262 l +590 1638 l + +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +ce} _d +/OE{2191 0 115 0 2060 1493 sc +2042 1493 m +2042 1323 l +1300 1323 l +1300 881 l +2011 881 l +2011 711 l +1300 711 l +1300 170 l +2060 170 l +2060 0 l +995 0 l +706 0 487 63 338 190 c +189 317 115 503 115 748 c +115 991 189 1176 338 1303 c +487 1430 706 1493 995 1493 c +2042 1493 l + +1098 1323 m +969 1323 l +755 1323 595 1275 488 1179 c +381 1084 328 940 328 748 c +328 555 381 411 488 314 c +595 218 755 170 969 170 c +1098 170 l +1098 1323 l + +ce} _d +/oe{2095 0 113 -29 1987 1147 sc +1802 660 m +1801 761 1773 842 1718 901 c +1663 961 1590 991 1499 991 c +1397 991 1315 962 1253 904 c +1192 846 1156 764 1147 659 c +1802 660 l + +1987 606 m +1987 516 l +1141 516 l +1149 389 1187 293 1255 226 c +1323 160 1418 127 1540 127 c +1611 127 1679 136 1746 153 c +1813 170 1879 196 1944 231 c +1944 57 l +1877 29 1809 8 1740 -7 c +1671 -22 1601 -29 1530 -29 c +1423 -29 1330 -11 1249 26 c +1168 63 1101 117 1047 190 c +1000 117 941 62 871 25 c +802 -11 720 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c +720 1147 802 1128 872 1091 c +943 1054 1000 1000 1044 928 c +1096 999 1161 1054 1238 1091 c +1315 1128 1402 1147 1497 1147 c +1648 1147 1767 1098 1855 1001 c +1943 904 1987 773 1987 606 c + +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +ce} _d +/Racute{1423 0 201 0 1364 1900 sc +716 1900 m +901 1900 l +673 1636 l +520 1636 l +716 1900 l + +909 700 m +952 685 994 654 1035 606 c +1076 558 1118 492 1159 408 c +1364 0 l +1147 0 l +956 383 l +907 483 859 549 812 582 c +766 615 703 631 623 631 c +403 631 l +403 0 l +201 0 l +201 1493 l +657 1493 l +828 1493 955 1457 1039 1386 c +1123 1315 1165 1207 1165 1063 c +1165 969 1143 891 1099 829 c +1056 767 992 724 909 700 c + +403 1327 m +403 797 l +657 797 l +754 797 828 819 877 864 c +927 909 952 976 952 1063 c +952 1150 927 1216 877 1260 c +828 1305 754 1327 657 1327 c +403 1327 l + +ce} _d +/racute{842 0 186 0 916 1645 sc +717 1645 m +916 1645 l +590 1269 l +437 1269 l +717 1645 l + +842 948 m +821 960 799 969 774 974 c +750 980 723 983 694 983 c +590 983 510 949 454 881 c +399 814 371 717 371 590 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +410 1014 460 1064 522 1097 c +584 1130 659 1147 748 1147 c +761 1147 775 1146 790 1144 c +805 1143 822 1140 841 1137 c +842 948 l + +ce} _d +/Rcommaaccent{1423 0 201 -482 1364 1493 sc +716 -162 m +927 -162 l +763 -482 l +634 -482 l +716 -162 l + +909 700 m +952 685 994 654 1035 606 c +1076 558 1118 492 1159 408 c +1364 0 l +1147 0 l +956 383 l +907 483 859 549 812 582 c +766 615 703 631 623 631 c +403 631 l +403 0 l +201 0 l +201 1493 l +657 1493 l +828 1493 955 1457 1039 1386 c +1123 1315 1165 1207 1165 1063 c +1165 969 1143 891 1099 829 c +1056 767 992 724 909 700 c + +403 1327 m +403 797 l +657 797 l +754 797 828 819 877 864 c +927 909 952 976 952 1063 c +952 1150 927 1216 877 1260 c +828 1305 754 1327 657 1327 c +403 1327 l + +ce} _d +/rcommaaccent{842 0 130 -482 842 1147 sc +212 -162 m +423 -162 l +259 -482 l +130 -482 l +212 -162 l + +842 948 m +821 960 799 969 774 974 c +750 980 723 983 694 983 c +590 983 510 949 454 881 c +399 814 371 717 371 590 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +410 1014 460 1064 522 1097 c +584 1130 659 1147 748 1147 c +761 1147 775 1146 790 1144 c +805 1143 822 1140 841 1137 c +842 948 l + +ce} _d +/Rcaron{1423 0 201 0 1364 1887 sc +909 700 m +952 685 994 654 1035 606 c +1076 558 1118 492 1159 408 c +1364 0 l +1147 0 l +956 383 l +907 483 859 549 812 582 c +766 615 703 631 623 631 c +403 631 l +403 0 l +201 0 l +201 1493 l +657 1493 l +828 1493 955 1457 1039 1386 c +1123 1315 1165 1207 1165 1063 c +1165 969 1143 891 1099 829 c +1056 767 992 724 909 700 c + +403 1327 m +403 797 l +657 797 l +754 797 828 819 877 864 c +927 909 952 976 952 1063 c +952 1150 927 1216 877 1260 c +828 1305 754 1327 657 1327 c +403 1327 l + +543 1621 m +332 1887 l +471 1887 l +637 1709 l +803 1887 l +942 1887 l +731 1621 l +543 1621 l + +ce} _d +/rcaron{842 0 186 0 858 1638 sc +842 948 m +821 960 799 969 774 974 c +750 980 723 983 694 983 c +590 983 510 949 454 881 c +399 814 371 717 371 590 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +410 1014 460 1064 522 1097 c +584 1130 659 1147 748 1147 c +761 1147 775 1146 790 1144 c +805 1143 822 1140 841 1137 c +842 948 l + +465 1262 m +220 1638 l +359 1638 l +539 1393 l +719 1638 l +858 1638 l +613 1262 l +465 1262 l + +ce} _d +/Sacute{1300 0 135 -29 1186 1900 sc +716 1900 m +901 1900 l +673 1636 l +520 1636 l +716 1900 l + +1096 1444 m +1096 1247 l +1019 1284 947 1311 879 1329 c +811 1347 745 1356 682 1356 c +572 1356 487 1335 427 1292 c +368 1249 338 1189 338 1110 c +338 1044 358 994 397 960 c +437 927 512 900 623 879 c +745 854 l +896 825 1007 775 1078 702 c +1150 630 1186 533 1186 412 c +1186 267 1137 158 1040 83 c +943 8 801 -29 614 -29 c +543 -29 468 -21 388 -5 c +309 11 226 35 141 66 c +141 274 l +223 228 303 193 382 170 c +461 147 538 135 614 135 c +729 135 818 158 881 203 c +944 248 975 313 975 397 c +975 470 952 528 907 569 c +862 610 789 641 686 662 c +563 686 l +412 716 303 763 236 827 c +169 891 135 980 135 1094 c +135 1226 181 1330 274 1406 c +367 1482 496 1520 659 1520 c +729 1520 800 1514 873 1501 c +946 1488 1020 1469 1096 1444 c + +ce} _d +/sacute{1067 0 111 -29 967 1645 sc +717 1645 m +916 1645 l +590 1269 l +437 1269 l +717 1645 l + +907 1087 m +907 913 l +855 940 801 960 745 973 c +689 986 631 993 571 993 c +480 993 411 979 365 951 c +320 923 297 881 297 825 c +297 782 313 749 346 724 c +379 700 444 677 543 655 c +606 641 l +737 613 829 573 884 522 c +939 471 967 400 967 309 c +967 205 926 123 843 62 c +761 1 648 -29 504 -29 c +444 -29 381 -23 316 -11 c +251 0 183 18 111 41 c +111 231 l +179 196 246 169 312 151 c +378 134 443 125 508 125 c +595 125 661 140 708 169 c +755 199 778 241 778 295 c +778 345 761 383 727 410 c +694 437 620 462 506 487 c +442 502 l +328 526 246 563 195 612 c +144 662 119 730 119 817 c +119 922 156 1004 231 1061 c +306 1118 412 1147 549 1147 c +617 1147 681 1142 741 1132 c +801 1122 856 1107 907 1087 c + +ce} _d +/Scircumflex{1300 0 135 -29 1186 1901 sc +565 1901 m +753 1901 l +964 1635 l +825 1635 l +659 1813 l +493 1635 l +354 1635 l +565 1901 l + +1096 1444 m +1096 1247 l +1019 1284 947 1311 879 1329 c +811 1347 745 1356 682 1356 c +572 1356 487 1335 427 1292 c +368 1249 338 1189 338 1110 c +338 1044 358 994 397 960 c +437 927 512 900 623 879 c +745 854 l +896 825 1007 775 1078 702 c +1150 630 1186 533 1186 412 c +1186 267 1137 158 1040 83 c +943 8 801 -29 614 -29 c +543 -29 468 -21 388 -5 c +309 11 226 35 141 66 c +141 274 l +223 228 303 193 382 170 c +461 147 538 135 614 135 c +729 135 818 158 881 203 c +944 248 975 313 975 397 c +975 470 952 528 907 569 c +862 610 789 641 686 662 c +563 686 l +412 716 303 763 236 827 c +169 891 135 980 135 1094 c +135 1226 181 1330 274 1406 c +367 1482 496 1520 659 1520 c +729 1520 800 1514 873 1501 c +946 1488 1020 1469 1096 1444 c + +ce} _d +/scircumflex{1067 0 111 -29 967 1638 sc +475 1638 m +623 1638 l +868 1262 l +729 1262 l +549 1507 l +369 1262 l +230 1262 l +475 1638 l + +907 1087 m +907 913 l +855 940 801 960 745 973 c +689 986 631 993 571 993 c +480 993 411 979 365 951 c +320 923 297 881 297 825 c +297 782 313 749 346 724 c +379 700 444 677 543 655 c +606 641 l +737 613 829 573 884 522 c +939 471 967 400 967 309 c +967 205 926 123 843 62 c +761 1 648 -29 504 -29 c +444 -29 381 -23 316 -11 c +251 0 183 18 111 41 c +111 231 l +179 196 246 169 312 151 c +378 134 443 125 508 125 c +595 125 661 140 708 169 c +755 199 778 241 778 295 c +778 345 761 383 727 410 c +694 437 620 462 506 487 c +442 502 l +328 526 246 563 195 612 c +144 662 119 730 119 817 c +119 922 156 1004 231 1061 c +306 1118 412 1147 549 1147 c +617 1147 681 1142 741 1132 c +801 1122 856 1107 907 1087 c + +ce} _d +/Scedilla{1300 0 135 -395 1186 1520 sc +1096 1444 m +1096 1247 l +1019 1284 947 1311 879 1329 c +811 1347 745 1356 682 1356 c +572 1356 487 1335 427 1292 c +368 1249 338 1189 338 1110 c +338 1044 358 994 397 960 c +437 927 512 900 623 879 c +745 854 l +896 825 1007 775 1078 702 c +1150 630 1186 533 1186 412 c +1186 267 1137 158 1040 83 c +943 8 801 -29 614 -29 c +543 -29 468 -21 388 -5 c +309 11 226 35 141 66 c +141 274 l +223 228 303 193 382 170 c +461 147 538 135 614 135 c +729 135 818 158 881 203 c +944 248 975 313 975 397 c +975 470 952 528 907 569 c +862 610 789 641 686 662 c +563 686 l +412 716 303 763 236 827 c +169 891 135 980 135 1094 c +135 1226 181 1330 274 1406 c +367 1482 496 1520 659 1520 c +729 1520 800 1514 873 1501 c +946 1488 1020 1469 1096 1444 c + +735 0 m +772 -41 799 -79 817 -114 c +835 -149 844 -183 844 -215 c +844 -274 824 -319 784 -349 c +744 -380 685 -395 606 -395 c +575 -395 545 -393 516 -389 c +487 -385 459 -379 430 -371 c +430 -240 l +453 -251 476 -259 501 -264 c +526 -269 554 -272 585 -272 c +624 -272 654 -264 674 -248 c +694 -232 704 -209 704 -178 c +704 -158 697 -133 682 -104 c +668 -75 646 -41 616 0 c +735 0 l + +ce} _d +/scedilla{1067 0 111 -395 967 1147 sc +907 1087 m +907 913 l +855 940 801 960 745 973 c +689 986 631 993 571 993 c +480 993 411 979 365 951 c +320 923 297 881 297 825 c +297 782 313 749 346 724 c +379 700 444 677 543 655 c +606 641 l +737 613 829 573 884 522 c +939 471 967 400 967 309 c +967 205 926 123 843 62 c +761 1 648 -29 504 -29 c +444 -29 381 -23 316 -11 c +251 0 183 18 111 41 c +111 231 l +179 196 246 169 312 151 c +378 134 443 125 508 125 c +595 125 661 140 708 169 c +755 199 778 241 778 295 c +778 345 761 383 727 410 c +694 437 620 462 506 487 c +442 502 l +328 526 246 563 195 612 c +144 662 119 730 119 817 c +119 922 156 1004 231 1061 c +306 1118 412 1147 549 1147 c +617 1147 681 1142 741 1132 c +801 1122 856 1107 907 1087 c + +619 0 m +656 -41 683 -79 701 -114 c +719 -149 728 -183 728 -215 c +728 -274 708 -319 668 -349 c +628 -380 569 -395 490 -395 c +459 -395 429 -393 400 -389 c +371 -385 343 -379 314 -371 c +314 -240 l +337 -251 360 -259 385 -264 c +410 -269 438 -272 469 -272 c +508 -272 538 -264 558 -248 c +578 -232 588 -209 588 -178 c +588 -158 581 -133 566 -104 c +552 -75 530 -41 500 0 c +619 0 l + +ce} _d +/Scaron{1300 0 135 -29 1186 1901 sc +1096 1444 m +1096 1247 l +1019 1284 947 1311 879 1329 c +811 1347 745 1356 682 1356 c +572 1356 487 1335 427 1292 c +368 1249 338 1189 338 1110 c +338 1044 358 994 397 960 c +437 927 512 900 623 879 c +745 854 l +896 825 1007 775 1078 702 c +1150 630 1186 533 1186 412 c +1186 267 1137 158 1040 83 c +943 8 801 -29 614 -29 c +543 -29 468 -21 388 -5 c +309 11 226 35 141 66 c +141 274 l +223 228 303 193 382 170 c +461 147 538 135 614 135 c +729 135 818 158 881 203 c +944 248 975 313 975 397 c +975 470 952 528 907 569 c +862 610 789 641 686 662 c +563 686 l +412 716 303 763 236 827 c +169 891 135 980 135 1094 c +135 1226 181 1330 274 1406 c +367 1482 496 1520 659 1520 c +729 1520 800 1514 873 1501 c +946 1488 1020 1469 1096 1444 c + +557 1635 m +346 1901 l +485 1901 l +651 1723 l +817 1901 l +956 1901 l +745 1635 l +557 1635 l + +ce} _d +/scaron{1067 0 111 -29 967 1638 sc +907 1087 m +907 913 l +855 940 801 960 745 973 c +689 986 631 993 571 993 c +480 993 411 979 365 951 c +320 923 297 881 297 825 c +297 782 313 749 346 724 c +379 700 444 677 543 655 c +606 641 l +737 613 829 573 884 522 c +939 471 967 400 967 309 c +967 205 926 123 843 62 c +761 1 648 -29 504 -29 c +444 -29 381 -23 316 -11 c +251 0 183 18 111 41 c +111 231 l +179 196 246 169 312 151 c +378 134 443 125 508 125 c +595 125 661 140 708 169 c +755 199 778 241 778 295 c +778 345 761 383 727 410 c +694 437 620 462 506 487 c +442 502 l +328 526 246 563 195 612 c +144 662 119 730 119 817 c +119 922 156 1004 231 1061 c +306 1118 412 1147 549 1147 c +617 1147 681 1142 741 1132 c +801 1122 856 1107 907 1087 c + +481 1262 m +236 1638 l +375 1638 l +555 1393 l +735 1638 l +874 1638 l +629 1262 l +481 1262 l + +551 1147 m +551 1147 l + +ce} _d +/Tcommaaccent{1251 0 -6 -395 1257 1493 sc +676 0 m +713 -41 740 -79 758 -114 c +776 -149 785 -183 785 -215 c +785 -274 765 -319 725 -349 c +685 -380 626 -395 547 -395 c +516 -395 486 -393 457 -389 c +428 -385 400 -379 371 -371 c +371 -240 l +394 -251 417 -259 442 -264 c +467 -269 495 -272 526 -272 c +565 -272 595 -264 615 -248 c +635 -232 645 -209 645 -178 c +645 -158 638 -133 623 -104 c +609 -75 587 -41 557 0 c +676 0 l + +-6 1493 m +1257 1493 l +1257 1323 l +727 1323 l +727 0 l +524 0 l +524 1323 l +-6 1323 l +-6 1493 l + +ce} _d +/tcommaaccent{803 0 55 -395 754 1438 sc +565 0 m +602 -41 629 -79 647 -114 c +665 -149 674 -183 674 -215 c +674 -274 654 -319 614 -349 c +574 -380 515 -395 436 -395 c +405 -395 375 -393 346 -389 c +317 -385 289 -379 260 -371 c +260 -240 l +283 -251 306 -259 331 -264 c +356 -269 384 -272 415 -272 c +454 -272 484 -264 504 -248 c +524 -232 534 -209 534 -178 c +534 -158 527 -133 512 -104 c +498 -75 476 -41 446 0 c +565 0 l + +375 1438 m +375 1120 l +754 1120 l +754 977 l +375 977 l +375 369 l +375 278 387 219 412 193 c +437 167 488 154 565 154 c +754 154 l +754 0 l +565 0 l +423 0 325 26 271 79 c +217 132 190 229 190 369 c +190 977 l +55 977 l +55 1120 l +190 1120 l +190 1438 l +375 1438 l + +ce} _d +/Tcaron{1251 0 -6 0 1257 1887 sc +-6 1493 m +1257 1493 l +1257 1323 l +727 1323 l +727 0 l +524 0 l +524 1323 l +-6 1323 l +-6 1493 l + +533 1621 m +322 1887 l +461 1887 l +627 1709 l +793 1887 l +932 1887 l +721 1621 l +533 1621 l + +ce} _d +/tcaron{803 0 55 0 766 1666 sc +375 1438 m +375 1120 l +754 1120 l +754 977 l +375 977 l +375 369 l +375 278 387 219 412 193 c +437 167 488 154 565 154 c +754 154 l +754 0 l +565 0 l +423 0 325 26 271 79 c +217 132 190 229 190 369 c +190 977 l +55 977 l +55 1120 l +190 1120 l +190 1438 l +375 1438 l + +567 1666 m +766 1666 l +649 1290 l +496 1290 l +567 1666 l + +ce} _d +/Tbar{1251 0 -6 0 1257 1493 sc +-6 1493 m +1257 1493 l +1257 1323 l +727 1323 l +727 747 l +992 747 l +992 577 l +727 577 l +727 0 l +524 0 l +524 577 l +259 577 l +259 747 l +524 747 l +524 1323 l +-6 1323 l +-6 1493 l + +ce} _d +/tbar{803 0 55 0 754 1438 sc +375 1438 m +375 1120 l +754 1120 l +754 977 l +375 977 l +375 744 l +754 744 l +754 602 l +375 602 l +375 369 l +375 278 387 219 412 193 c +437 167 488 154 565 154 c +754 154 l +754 0 l +565 0 l +423 0 325 27 271 80 c +217 133 190 229 190 369 c +190 602 l +55 602 l +55 744 l +190 744 l +190 977 l +55 977 l +55 1120 l +190 1120 l +190 1438 l +375 1438 l + +ce} _d +/Utilde{1499 0 178 -29 1321 1886 sc +746 1710 m +689 1743 l +672 1752 659 1759 648 1762 c +638 1766 629 1768 621 1768 c +597 1768 578 1760 565 1743 c +552 1726 545 1703 545 1673 c +545 1667 l +420 1667 l +420 1734 437 1788 471 1827 c +506 1866 552 1886 609 1886 c +633 1886 655 1883 675 1878 c +696 1873 722 1861 754 1843 c +811 1813 l +826 1804 840 1798 851 1794 c +862 1790 873 1788 883 1788 c +904 1788 922 1796 935 1813 c +948 1830 955 1853 955 1880 c +955 1886 l +1080 1886 l +1079 1819 1061 1766 1026 1726 c +992 1687 947 1667 891 1667 c +868 1667 847 1670 827 1675 c +808 1680 781 1692 746 1710 c + +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +ce} _d +/utilde{1298 0 174 -29 1112 1591 sc +639 1370 m +582 1425 l +567 1438 554 1448 543 1454 c +532 1461 523 1464 514 1464 c +489 1464 470 1452 458 1427 c +446 1403 439 1364 438 1309 c +313 1309 l +314 1399 332 1468 366 1517 c +400 1566 447 1591 508 1591 c +533 1591 557 1586 578 1577 c +599 1568 622 1552 647 1530 c +704 1475 l +719 1462 731 1452 742 1445 c +753 1439 763 1436 772 1436 c +797 1436 816 1448 828 1472 c +840 1497 847 1536 848 1591 c +973 1591 l +972 1501 954 1431 920 1382 c +886 1333 839 1309 778 1309 c +753 1309 729 1314 708 1323 c +687 1332 664 1348 639 1370 c + +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +ce} _d +/Umacron{1499 0 178 -29 1321 1841 sc +451 1841 m +1049 1841 l +1049 1693 l +451 1693 l +451 1841 l + +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +ce} _d +/umacron{1298 0 174 -29 1112 1525 sc +344 1525 m +942 1525 l +942 1377 l +344 1377 l +344 1525 l + +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +ce} _d +/Ubreve{1499 0 178 -29 1321 1901 sc +437 1901 m +555 1901 l +564 1865 584 1837 617 1818 c +650 1799 695 1790 750 1790 c +805 1790 848 1799 880 1817 c +913 1836 934 1864 945 1901 c +1063 1901 l +1056 1822 1026 1761 973 1720 c +920 1679 845 1659 750 1659 c +654 1659 579 1679 526 1720 c +473 1761 444 1821 437 1901 c + +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +ce} _d +/ubreve{1298 0 174 -29 1112 1608 sc +330 1608 m +448 1608 l +455 1558 475 1520 507 1495 c +540 1470 585 1458 643 1458 c +700 1458 745 1470 777 1495 c +809 1520 829 1557 838 1608 c +956 1608 l +949 1513 920 1441 867 1393 c +814 1345 740 1321 643 1321 c +546 1321 472 1345 419 1393 c +366 1441 337 1513 330 1608 c + +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +ce} _d +/Uring{1499 0 178 -29 1321 1903 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +904 1629 m +904 1671 889 1707 860 1736 c +831 1765 795 1780 752 1780 c +709 1780 672 1765 643 1736 c +614 1707 600 1672 600 1629 c +600 1586 614 1549 643 1520 c +672 1491 709 1477 752 1477 c +795 1477 831 1492 860 1521 c +889 1550 904 1586 904 1629 c + +1026 1629 m +1026 1552 999 1487 946 1434 c +893 1381 829 1354 752 1354 c +675 1354 610 1381 557 1434 c +504 1487 478 1552 478 1629 c +478 1706 504 1770 557 1823 c +610 1876 675 1903 752 1903 c +829 1903 893 1876 946 1823 c +999 1770 1026 1706 1026 1629 c + +ce} _d +/uring{1298 0 174 -29 1112 1738 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +788 1464 m +788 1506 773 1542 744 1571 c +715 1600 679 1615 636 1615 c +593 1615 556 1600 527 1571 c +498 1542 484 1507 484 1464 c +484 1421 498 1384 527 1355 c +556 1326 593 1312 636 1312 c +679 1312 715 1327 744 1356 c +773 1385 788 1421 788 1464 c + +910 1464 m +910 1387 883 1322 830 1269 c +777 1216 713 1189 636 1189 c +559 1189 494 1216 441 1269 c +388 1322 362 1387 362 1464 c +362 1541 388 1605 441 1658 c +494 1711 559 1738 636 1738 c +713 1738 777 1711 830 1658 c +883 1605 910 1541 910 1464 c + +ce} _d +/Uhungarumlaut{1499 0 178 -29 1321 1899 sc +999 1899 m +1184 1899 l +956 1635 l +803 1635 l +999 1899 l + +664 1899 m +849 1899 l +621 1635 l +468 1635 l +664 1899 l + +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +ce} _d +/uhungarumlaut{1298 0 174 -29 1118 1638 sc +940 1638 m +1118 1638 l +870 1262 l +735 1262 l +940 1638 l + +606 1638 m +776 1638 l +553 1262 l +416 1262 l +606 1638 l + +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +ce} _d +/Uogonek{1499 0 178 -395 1321 1493 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +690 0 m +809 0 l +779 -41 757 -76 742 -105 c +728 -134 721 -159 721 -180 c +721 -211 730 -234 748 -249 c +767 -264 794 -272 830 -272 c +851 -272 872 -269 893 -264 c +914 -259 934 -252 955 -242 c +955 -375 l +930 -382 906 -387 883 -390 c +860 -393 839 -395 819 -395 c +738 -395 678 -380 639 -351 c +601 -322 582 -277 582 -215 c +582 -183 591 -149 608 -114 c +626 -79 653 -41 690 0 c + +ce} _d +/uogonek{1298 0 174 -395 1256 1147 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +991 0 m +1110 0 l +1080 -41 1058 -76 1043 -105 c +1029 -134 1022 -159 1022 -180 c +1022 -211 1031 -234 1049 -249 c +1068 -264 1095 -272 1131 -272 c +1152 -272 1173 -269 1194 -264 c +1215 -259 1235 -252 1256 -242 c +1256 -375 l +1231 -382 1207 -387 1184 -390 c +1161 -393 1140 -395 1120 -395 c +1039 -395 979 -380 940 -351 c +902 -322 883 -277 883 -215 c +883 -183 892 -149 909 -114 c +927 -79 954 -41 991 0 c + +ce} _d +/Wcircumflex{2025 0 68 0 1958 1908 sc +919 1908 m +1107 1908 l +1318 1642 l +1179 1642 l +1013 1820 l +847 1642 l +708 1642 l +919 1908 l + +68 1493 m +272 1493 l +586 231 l +899 1493 l +1126 1493 l +1440 231 l +1753 1493 l +1958 1493 l +1583 0 l +1329 0 l +1014 1296 l +696 0 l +442 0 l +68 1493 l + +ce} _d +/wcircumflex{1675 0 86 0 1589 1645 sc +763 1645 m +911 1645 l +1156 1269 l +1017 1269 l +837 1514 l +657 1269 l +518 1269 l +763 1645 l + +86 1120 m +270 1120 l +500 246 l +729 1120 l +946 1120 l +1176 246 l +1405 1120 l +1589 1120 l +1296 0 l +1079 0 l +838 918 l +596 0 l +379 0 l +86 1120 l + +ce} _d +/Ycircumflex{1251 0 -4 0 1255 1908 sc +532 1908 m +720 1908 l +931 1642 l +792 1642 l +626 1820 l +460 1642 l +321 1642 l +532 1908 l + +-4 1493 m +213 1493 l +627 879 l +1038 1493 l +1255 1493 l +727 711 l +727 0 l +524 0 l +524 711 l +-4 1493 l + +ce} _d +/ycircumflex{1212 0 61 -426 1151 1645 sc +532 1645 m +680 1645 l +925 1269 l +786 1269 l +606 1514 l +426 1269 l +287 1269 l +532 1645 l + +659 -104 m +607 -237 556 -324 507 -365 c +458 -406 392 -426 309 -426 c +162 -426 l +162 -272 l +270 -272 l +321 -272 360 -260 388 -236 c +416 -212 447 -155 481 -66 c +514 18 l +61 1120 l +256 1120 l +606 244 l +956 1120 l +1151 1120 l +659 -104 l + +ce} _d +/Ydieresis{1251 0 -4 0 1255 1870 sc +-4 1493 m +213 1493 l +627 879 l +1038 1493 l +1255 1493 l +727 711 l +727 0 l +524 0 l +524 711 l +-4 1493 l + +721 1870 m +924 1870 l +924 1667 l +721 1667 l +721 1870 l + +330 1870 m +533 1870 l +533 1667 l +330 1667 l +330 1870 l + +ce} _d +/Zacute{1403 0 92 0 1311 1900 sc +716 1900 m +901 1900 l +673 1636 l +520 1636 l +716 1900 l + +115 1493 m +1288 1493 l +1288 1339 l +344 170 l +1311 170 l +1311 0 l +92 0 l +92 154 l +1036 1323 l +115 1323 l +115 1493 l + +ce} _d +/zacute{1075 0 88 0 987 1645 sc +717 1645 m +916 1645 l +590 1269 l +437 1269 l +717 1645 l + +113 1120 m +987 1120 l +987 952 l +295 147 l +987 147 l +987 0 l +88 0 l +88 168 l +780 973 l +113 973 l +113 1120 l + +ce} _d +/Zdotaccent{1403 0 92 0 1311 1872 sc +600 1872 m +804 1872 l +804 1667 l +600 1667 l +600 1872 l + +115 1493 m +1288 1493 l +1288 1339 l +344 170 l +1311 170 l +1311 0 l +92 0 l +92 154 l +1036 1323 l +115 1323 l +115 1493 l + +ce} _d +/zdotaccent{1075 0 88 0 987 1556 sc +441 1556 m +625 1556 l +625 1323 l +441 1323 l +441 1556 l + +535 1147 m +535 1147 l + +113 1120 m +987 1120 l +987 952 l +295 147 l +987 147 l +987 0 l +88 0 l +88 168 l +780 973 l +113 973 l +113 1120 l + +ce} _d +/Zcaron{1403 0 92 0 1311 1901 sc +115 1493 m +1288 1493 l +1288 1339 l +344 170 l +1311 170 l +1311 0 l +92 0 l +92 154 l +1036 1323 l +115 1323 l +115 1493 l + +608 1635 m +397 1901 l +536 1901 l +702 1723 l +868 1901 l +1007 1901 l +796 1635 l +608 1635 l + +ce} _d +/zcaron{1075 0 88 0 987 1638 sc +113 1120 m +987 1120 l +987 952 l +295 147 l +987 147 l +987 0 l +88 0 l +88 168 l +780 973 l +113 973 l +113 1120 l + +465 1262 m +220 1638 l +359 1638 l +539 1393 l +719 1638 l +858 1638 l +613 1262 l +465 1262 l + +ce} _d +/longs{721 0 47 0 760 1556 sc +408 0 m +223 0 l +223 977 l +47 977 l +47 1120 l +223 1120 l +223 1198 l +223 1323 252 1413 310 1470 c +368 1527 460 1556 586 1556 c +760 1556 l +760 1403 l +584 1403 l +518 1403 472 1390 446 1363 c +421 1336 408 1288 408 1219 c +408 0 l + +ce} _d +/uni0180{1300 0 32 -29 1188 1556 sc +997 559 m +997 694 969 801 914 878 c +858 955 781 993 684 993 c +587 993 510 955 454 878 c +399 801 371 694 371 559 c +371 424 399 317 454 240 c +510 163 587 125 684 125 c +781 125 858 163 914 240 c +969 317 997 424 997 559 c + +371 950 m +410 1017 459 1066 518 1098 c +577 1131 647 1147 729 1147 c +865 1147 975 1093 1060 985 c +1145 877 1188 735 1188 559 c +1188 383 1145 241 1060 133 c +975 25 865 -29 729 -29 c +647 -29 577 -13 518 20 c +459 52 410 101 371 168 c +371 0 l +186 0 l +186 1284 l +32 1284 l +32 1409 l +186 1409 l +186 1556 l +371 1556 l +371 1409 l +696 1409 l +696 1284 l +371 1284 l +371 950 l + +ce} _d +/uni0181{1505 0 -105 0 1360 1493 sc +503 713 m +503 166 l +827 166 l +936 166 1016 188 1068 233 c +1121 278 1147 347 1147 440 c +1147 533 1121 602 1068 646 c +1016 691 936 713 827 713 c +503 713 l + +503 1327 m +503 877 l +802 877 l +901 877 974 895 1022 932 c +1071 969 1095 1026 1095 1102 c +1095 1177 1071 1234 1022 1271 c +974 1308 901 1327 802 1327 c +503 1327 l + +301 1493 m +817 1493 l +971 1493 1090 1461 1173 1397 c +1256 1333 1298 1242 1298 1124 c +1298 1033 1277 960 1234 906 c +1191 852 1129 818 1046 805 c +1145 784 1222 739 1277 671 c +1332 604 1360 519 1360 418 c +1360 285 1315 182 1224 109 c +1133 36 1004 0 837 0 c +301 0 l +301 1328 l +213 1328 149 1312 110 1280 c +71 1249 51 1198 51 1128 c +51 1079 l +-105 1079 l +-105 1149 l +-105 1270 -73 1357 -9 1411 c +55 1466 158 1493 301 1493 c + +ce} _d +/uni0182{1405 0 201 0 1260 1493 sc +1047 439 m +1047 532 1021 600 968 645 c +916 690 836 713 727 713 c +403 713 l +403 166 l +727 166 l +836 166 916 188 968 233 c +1021 278 1047 347 1047 439 c + +1155 1493 m +1155 1327 l +403 1327 l +403 879 l +737 879 l +904 879 1033 843 1124 770 c +1215 697 1260 587 1260 439 c +1260 292 1216 182 1128 109 c +1041 36 910 0 737 0 c +201 0 l +201 1493 l +1155 1493 l + +ce} _d +/uni0183{1300 0 186 -29 1188 1556 sc +371 950 m +410 1017 459 1066 518 1098 c +577 1131 647 1147 729 1147 c +865 1147 975 1093 1060 985 c +1145 877 1188 735 1188 559 c +1188 383 1145 241 1060 133 c +975 25 865 -29 729 -29 c +647 -29 577 -13 518 20 c +459 52 410 101 371 168 c +371 0 l +186 0 l +186 1556 l +1032 1556 l +1032 1390 l +371 1391 l +371 950 l + +997 559 m +997 694 969 801 914 878 c +858 955 781 993 684 993 c +587 993 510 955 454 878 c +399 801 371 694 371 559 c +371 424 399 317 454 240 c +510 163 587 125 684 125 c +781 125 858 163 914 240 c +969 317 997 424 997 559 c + +ce} _d +/uni0184{1405 0 0 0 1260 1493 sc +1047 439 m +1047 532 1021 601 968 646 c +916 691 836 713 727 713 c +403 713 l +403 166 l +727 166 l +836 166 916 189 968 234 c +1021 279 1047 347 1047 439 c + +403 1493 m +403 879 l +737 879 l +904 879 1033 843 1124 770 c +1215 697 1260 587 1260 439 c +1260 292 1215 182 1124 109 c +1033 36 904 0 737 0 c +201 0 l +201 1092 l +0 1092 l +312 1493 l +403 1493 l + +ce} _d +/uni0185{1300 0 0 -29 1188 1557 sc +371 950 m +410 1017 458 1066 517 1098 c +576 1131 647 1147 729 1147 c +865 1147 975 1093 1060 985 c +1145 877 1188 735 1188 559 c +1188 383 1145 241 1060 133 c +975 25 865 -29 729 -29 c +647 -29 576 -13 517 19 c +458 52 410 101 371 168 c +371 0 l +186 0 l +186 1092 l +0 1092 l +290 1557 l +371 1557 l +371 950 l + +997 559 m +997 694 969 800 913 877 c +858 954 781 993 684 993 c +587 993 510 954 454 877 c +399 800 371 694 371 559 c +371 424 399 317 454 240 c +510 163 587 125 684 125 c +781 125 858 163 913 240 c +969 317 997 424 997 559 c + +ce} _d +/uni0186{1440 0 115 -29 1319 1520 sc +115 1378 m +184 1425 258 1461 337 1484 c +416 1508 501 1520 590 1520 c +816 1520 994 1451 1124 1312 c +1254 1174 1319 985 1319 745 c +1319 506 1254 317 1124 178 c +994 40 816 -29 590 -29 c +502 -29 418 -17 339 7 c +260 31 186 67 115 115 c +115 326 l +183 263 255 215 332 184 c +409 153 491 137 578 137 c +749 137 879 189 970 293 c +1061 398 1106 548 1106 745 c +1106 942 1061 1093 970 1197 c +879 1302 749 1354 578 1354 c +491 1354 409 1338 332 1307 c +255 1276 183 1228 115 1165 c +115 1378 l + +ce} _d +/uni0187{1430 0 115 -29 1626 1892 sc +1319 1378 m +1319 1165 l +1251 1228 1178 1276 1101 1307 c +1024 1338 943 1354 856 1354 c +685 1354 555 1302 464 1197 c +373 1093 328 942 328 745 c +328 548 373 398 464 293 c +555 189 685 137 856 137 c +943 137 1024 153 1101 184 c +1178 215 1251 263 1319 326 c +1319 115 l +1248 67 1173 31 1094 7 c +1015 -17 932 -29 844 -29 c +618 -29 440 40 310 178 c +180 317 115 506 115 745 c +115 985 180 1174 310 1312 c +440 1451 618 1520 844 1520 c +908 1520 992 1508 1096 1484 c +1105 1482 1113 1480 1121 1477 c +1132 1607 1165 1705 1220 1770 c +1288 1851 1398 1892 1549 1892 c +1626 1892 l +1626 1722 l +1563 1722 l +1474 1722 1411 1697 1374 1647 c +1337 1597 1319 1507 1319 1378 c + +ce} _d +/uni0188{1126 0 113 -29 1228 1556 sc +999 1150 m +999 905 l +947 934 895 955 842 969 c +790 984 737 991 684 991 c +565 991 472 953 406 877 c +340 802 307 696 307 559 c +307 422 340 316 406 240 c +472 165 565 127 684 127 c +737 127 790 134 842 148 c +895 163 947 184 999 213 c +999 43 l +948 19 894 1 839 -11 c +784 -23 726 -29 664 -29 c +495 -29 361 24 262 130 c +163 236 113 379 113 559 c +113 742 163 885 263 990 c +364 1095 501 1147 676 1147 c +723 1147 770 1143 817 1135 c +817 1150 l +817 1293 844 1396 897 1460 c +951 1524 1038 1556 1159 1556 c +1228 1556 l +1228 1400 l +1180 1400 l +1110 1400 1062 1384 1037 1351 c +1012 1319 999 1252 999 1150 c + +ce} _d +/uni0189{1587 0 10 0 1466 1493 sc +211 1493 m +627 1493 l +916 1493 1128 1433 1263 1312 c +1398 1192 1466 1004 1466 748 c +1466 491 1398 302 1262 181 c +1127 60 915 0 627 0 c +211 0 l +211 700 l +10 700 l +10 844 l +211 844 l +211 1493 l + +414 1327 m +414 844 l +750 844 l +750 700 l +414 700 l +414 166 l +657 166 l +863 166 1014 213 1109 306 c +1205 399 1253 547 1253 748 c +1253 948 1205 1094 1109 1187 c +1014 1280 863 1327 657 1327 c +414 1327 l + +ce} _d +/uni018A{1677 0 -105 0 1556 1493 sc +503 1327 m +503 166 l +747 166 l +953 166 1104 213 1199 306 c +1295 399 1343 547 1343 748 c +1343 948 1295 1094 1199 1187 c +1104 1280 953 1327 747 1327 c +503 1327 l + +301 1493 m +716 1493 l +1005 1493 1218 1433 1353 1312 c +1488 1192 1556 1004 1556 748 c +1556 491 1488 302 1352 181 c +1216 60 1004 0 716 0 c +301 0 l +301 1328 l +213 1328 149 1312 110 1280 c +71 1249 51 1198 51 1128 c +51 1079 l +-105 1079 l +-105 1149 l +-105 1270 -73 1357 -9 1411 c +55 1466 158 1493 301 1493 c + +ce} _d +/uni018B{1405 0 201 0 1260 1493 sc +414 439 m +414 257 521 166 734 166 c +1058 166 l +1058 713 l +734 713 l +625 713 545 690 492 645 c +440 600 414 532 414 439 c + +414 1493 m +1260 1493 l +1260 0 l +724 0 l +557 0 428 36 337 109 c +246 182 201 292 201 440 c +201 587 246 697 337 770 c +428 843 557 879 724 879 c +1058 879 l +1058 1327 l +414 1327 l +414 1493 l + +ce} _d +/uni018C{1300 0 113 -29 1114 1556 sc +269 1390 m +269 1556 l +1114 1556 l +1114 0 l +930 0 l +930 168 l +891 101 842 52 783 19 c +724 -13 654 -29 571 -29 c +436 -29 325 25 240 133 c +155 241 113 383 113 559 c +113 735 155 877 240 985 c +325 1093 436 1147 571 1147 c +654 1147 724 1131 783 1098 c +842 1066 891 1017 930 950 c +930 1391 l +269 1390 l + +303 559 m +303 424 331 317 386 240 c +442 163 519 125 616 125 c +713 125 790 163 846 240 c +902 317 930 424 930 559 c +930 694 902 800 846 877 c +790 954 713 993 616 993 c +519 993 442 954 386 877 c +331 800 303 694 303 559 c + +ce} _d +/uni018D{1253 0 113 -426 1141 1123 sc +875 66 m +980 13 1032 -60 1032 -154 c +1032 -335 885 -426 591 -426 c +444 -426 330 -403 250 -356 c +250 -203 l +318 -250 434 -273 598 -273 c +762 -273 844 -234 844 -156 c +844 -95 756 -48 580 -16 c +441 9 333 58 255 133 c +160 223 113 358 113 539 c +113 720 159 862 250 966 c +341 1071 467 1123 626 1123 c +786 1123 912 1071 1003 966 c +1095 862 1141 718 1140 535 c +1140 431 1114 336 1062 249 c +1011 162 948 101 875 66 c + +946 535 m +947 670 918 776 861 852 c +804 929 727 967 628 967 c +529 967 451 928 394 851 c +337 774 308 670 308 540 c +308 411 339 313 402 246 c +465 180 538 143 622 136 c +665 132 703 125 737 116 c +803 144 854 195 891 268 c +928 341 946 430 946 535 c + +ce} _d +/uni018E{1294 0 131 0 1093 1493 sc +1093 1493 m +1093 0 l +131 0 l +131 170 l +891 170 l +891 711 l +180 711 l +180 881 l +891 881 l +891 1323 l +149 1323 l +149 1493 l +1093 1493 l + +ce} _d +/uni018F{1612 0 117 -29 1497 1520 sc +117 780 m +1284 780 l +1284 959 1238 1099 1146 1201 c +1055 1303 918 1354 735 1354 c +642 1354 554 1338 470 1306 c +386 1274 307 1226 232 1163 c +232 1378 l +306 1425 387 1460 474 1484 c +562 1508 655 1520 752 1520 c +985 1520 1168 1452 1299 1315 c +1431 1179 1497 989 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +588 -29 418 44 297 190 c +177 337 117 533 117 780 c + +337 614 m +346 484 392 372 477 277 c +562 182 672 135 807 135 c +942 135 1051 182 1136 277 c +1221 372 1268 484 1277 614 c +337 614 l + +ce} _d +/uni0190{1258 0 164 -29 1147 1520 sc +472 805 m +385 827 317 866 270 923 c +223 980 199 1050 199 1133 c +199 1252 244 1346 333 1415 c +422 1485 544 1520 697 1520 c +756 1520 819 1515 886 1504 c +953 1493 1025 1477 1102 1456 c +1102 1276 l +1026 1301 956 1320 893 1332 c +830 1344 770 1350 715 1350 c +614 1350 536 1329 481 1288 c +427 1247 400 1189 400 1112 c +400 1037 426 980 479 940 c +532 901 608 881 707 881 c +889 881 l +889 715 l +715 715 l +605 715 519 690 457 640 c +396 591 365 522 365 434 c +365 339 398 266 464 216 c +531 166 627 141 754 141 c +827 141 896 149 963 166 c +1030 183 1091 207 1147 240 c +1147 45 l +1076 20 1008 2 941 -10 c +875 -23 811 -29 748 -29 c +561 -29 417 11 316 92 c +215 173 164 287 164 434 c +164 530 191 611 245 676 c +300 741 375 784 472 805 c + +ce} _d +/uni0191{1178 0 -106 -410 1059 1493 sc +201 1493 m +1059 1493 l +1059 1323 l +403 1323 l +403 883 l +995 883 l +995 713 l +403 713 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 +/florin{721 0 -129 -426 760 1556 sc +760 1556 m +760 1403 l +584 1403 l +518 1403 472 1390 446 1363 c +421 1336 408 1288 408 1219 c +408 1120 l +711 1120 l +711 977 l +408 977 l +408 -68 l +408 -193 379 -283 321 -340 c +263 -397 171 -426 45 -426 c +-129 -426 l +-129 -273 l +47 -273 l +113 -273 159 -260 184 -233 c +210 -206 223 -158 223 -89 c +223 977 l +47 977 l +47 1120 l +223 1120 l +223 1198 l +223 1323 252 1413 310 1470 c +368 1527 460 1556 586 1556 c +760 1556 l + +ce} _d +/uni0193{1587 0 115 -29 1687 1892 sc +1219 213 m +1219 614 l +889 614 l +889 780 l +1419 780 l +1419 139 l +1341 84 1255 42 1161 13 c +1067 -15 967 -29 860 -29 c +627 -29 444 39 312 175 c +181 312 115 502 115 745 c +115 989 181 1179 312 1315 c +444 1452 627 1520 860 1520 c +921 1520 978 1516 1032 1507 c +1087 1499 1137 1487 1182 1470 c +1182 1595 1215 1697 1282 1775 c +1349 1853 1459 1892 1610 1892 c +1687 1892 l +1687 1722 l +1624 1722 l +1535 1722 1472 1697 1435 1647 c +1398 1597 1380 1507 1380 1378 c +1380 1163 l +1305 1226 1226 1274 1142 1306 c +1058 1338 970 1354 877 1354 c +694 1354 557 1303 465 1201 c +374 1099 328 947 328 745 c +328 544 374 392 465 290 c +557 188 694 137 877 137 c +948 137 1012 143 1068 155 c +1124 168 1174 187 1219 213 c + +ce} _d +/uni0194{1406 0 8 -430 1398 1493 sc +703 -259 m +739 -259 772 -248 801 -227 c +820 -214 829 -185 829 -141 c +829 -103 819 -60 798 -11 c +764 70 732 141 703 202 c +674 141 642 70 608 -11 c +587 -60 577 -103 577 -141 c +577 -185 586 -214 605 -227 c +634 -248 667 -259 703 -259 c + +703 631 m +1176 1493 l +1398 1493 l +816 420 l +885 287 942 162 987 46 c +1018 -33 1033 -95 1033 -139 c +1033 -232 1008 -300 958 -343 c +891 -401 806 -430 703 -430 c +600 -430 515 -401 448 -343 c +398 -300 373 -232 373 -139 c +373 -95 388 -33 419 46 c +464 162 521 287 590 420 c +8 1493 l +230 1493 l +703 631 l + +ce} _d +/uni0195{2015 0 186 0 1863 1556 sc +1356 156 m +1455 156 1533 189 1589 254 c +1647 321 1676 407 1676 510 c +1676 658 1651 769 1602 844 c +1561 907 1500 950 1419 972 c +1419 1120 l +1568 1101 1679 1043 1752 948 c +1826 851 1863 711 1863 527 c +1863 364 1815 235 1719 141 c +1623 47 1501 0 1354 0 c +1284 0 l +1159 0 1071 33 1018 100 c +966 167 940 269 940 406 c +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1556 l +371 1556 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1027 c +1091 948 1124 831 1124 676 c +1124 406 l +1124 308 1137 242 1162 207 c +1187 173 1235 156 1305 156 c +1356 156 l + +ce} _d +/uni0196{724 0 201 0 710 1493 sc +201 1493 m +403 1493 l +403 514 l +403 385 421 295 458 245 c +495 195 558 170 647 170 c +710 170 l +710 0 l +633 0 l +482 0 372 41 303 122 c +235 203 201 334 201 514 c +201 1493 l + +ce} _d +/uni0197{604 0 10 0 594 1493 sc +201 1493 m +403 1493 l +403 747 l +594 747 l +594 577 l +403 577 l +403 0 l +201 0 l +201 577 l +10 577 l +10 747 l +201 747 l +201 1493 l + +ce} _d +/uni0198{1527 0 201 0 1527 1520 sc +1527 1096 m +1357 1096 l +1357 1217 l +1357 1253 1345 1284 1320 1311 c +1296 1338 1271 1351 1246 1351 c +1199 1351 1164 1339 1139 1316 c +592 797 l +1386 0 l +1120 0 l +403 719 l +403 0 l +201 0 l +201 1493 l +403 1493 l +403 862 l +1023 1441 l +1080 1494 1146 1520 1221 1520 c +1312 1520 1385 1489 1442 1428 c +1499 1367 1527 1300 1527 1227 c +1527 1096 l + +ce} _d +/uni0199{1186 0 185 0 1180 1556 sc +185 1150 m +185 1293 212 1396 266 1460 c +321 1524 408 1556 529 1556 c +720 1556 l +720 1400 l +552 1400 l +482 1400 434 1384 409 1351 c +384 1319 371 1252 371 1150 c +371 637 l +920 1120 l +1155 1120 l +561 596 l +1180 0 l +940 0 l +371 547 l +371 0 l +186 0 l +185 1150 l + +ce} _d +/uni019A{569 0 10 0 554 1556 sc +193 1556 m +377 1556 l +377 844 l +554 844 l +554 700 l +377 700 l +377 0 l +193 0 l +193 700 l +10 700 l +10 844 l +193 844 l +193 1556 l + +ce} _d +/uni019B{1212 0 61 0 1151 1556 sc +61 0 m +552 1074 l +481 1262 l +181 1161 l +148 1260 l +445 1359 l +370 1556 l +570 1556 l +622 1418 l +936 1522 l +969 1425 l +658 1321 l +1151 0 l +956 0 l +642 828 l +256 0 l +61 0 l + +ce} _d +/uni019C{1995 0 178 -29 1831 1493 sc +934 213 m +888 130 833 69 769 30 c +705 -9 630 -29 543 -29 c +426 -29 336 12 273 94 c +210 175 178 291 178 442 c +178 1493 l +381 1493 l +381 452 l +381 328 394 248 420 213 c +458 161 516 135 594 135 c +689 135 765 167 820 230 c +875 293 903 380 903 489 c +903 1493 l +1106 1493 l +1106 452 l +1106 344 1125 264 1163 212 c +1201 161 1260 135 1339 135 c +1421 135 1490 167 1545 230 c +1600 294 1628 380 1628 489 c +1628 1493 l +1831 1493 l +1831 -2 l +1628 -2 l +1628 172 l +1586 103 1536 53 1477 20 c +1418 -13 1349 -29 1268 -29 c +1187 -29 1117 -8 1060 33 c +1003 74 961 134 934 213 c + +ce} _d +/uni019D{1532 0 -106 -410 1331 1493 sc +201 1493 m +473 1493 l +1135 244 l +1135 1493 l +1331 1493 l +1331 0 l +1059 0 l +397 1249 l +397 104 l +397 -76 363 -207 294 -288 c +226 -369 116 -410 -35 -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 +/uni019E{1298 0 186 -426 1124 1147 sc +1124 676 m +1124 -426 l +940 -426 l +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1028 c +1091 948 1124 831 1124 676 c + +ce} _d +/uni019F{1612 0 115 -29 1497 1520 sc +115 745 m +115 981 178 1169 303 1309 c +429 1450 597 1520 806 1520 c +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 746 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 806 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c + +808 1356 m +673 1356 563 1309 478 1214 c +393 1119 346 1007 338 877 c +1278 877 l +1269 1007 1222 1119 1137 1214 c +1052 1309 943 1356 808 1356 c + +328 710 m +333 539 378 400 461 294 c +545 188 660 135 807 135 c +954 135 1068 188 1151 293 c +1234 399 1278 538 1283 710 c +328 710 l + +ce} _d +/Ohorn{1870 0 103 -29 1565 1556 sc +795 1356 m +648 1356 532 1301 445 1192 c +359 1083 316 934 316 745 c +316 557 359 408 445 299 c +532 190 648 135 795 135 c +942 135 1058 190 1143 299 c +1229 408 1272 557 1272 745 c +1272 934 1229 1083 1143 1192 c +1058 1301 942 1356 795 1356 c + +795 1520 m +1004 1520 1172 1450 1297 1309 c +1422 1169 1485 981 1485 745 c +1485 510 1422 322 1297 181 c +1172 41 1004 -29 795 -29 c +585 -29 417 41 291 181 c +166 321 103 509 103 745 c +103 981 166 1169 291 1309 c +417 1450 585 1520 795 1520 c + +1170 1291 m +1170 1410 l +1211 1380 1246 1358 1275 1343 c +1304 1329 1329 1322 1350 1322 c +1381 1322 1404 1331 1419 1349 c +1434 1368 1442 1395 1442 1431 c +1442 1452 1439 1473 1434 1494 c +1429 1515 1422 1535 1412 1556 c +1545 1556 l +1552 1531 1557 1507 1560 1484 c +1563 1461 1565 1440 1565 1420 c +1565 1339 1550 1279 1521 1240 c +1492 1202 1447 1183 1385 1183 c +1353 1183 1319 1192 1284 1209 c +1249 1227 1211 1254 1170 1291 c + +ce} _d +/ohorn{1253 0 118 -29 1235 1259 sc +840 994 m +840 1113 l +881 1083 916 1061 945 1046 c +974 1032 999 1025 1020 1025 c +1051 1025 1074 1034 1089 1052 c +1104 1071 1112 1098 1112 1134 c +1112 1155 1109 1176 1104 1197 c +1099 1218 1092 1238 1082 1259 c +1215 1259 l +1222 1234 1227 1210 1230 1187 c +1233 1164 1235 1143 1235 1123 c +1235 1042 1220 982 1191 943 c +1162 905 1117 886 1055 886 c +1023 886 989 895 954 912 c +919 930 881 957 840 994 c + +632 991 m +533 991 455 952 398 875 c +341 798 312 693 312 559 c +312 425 340 319 397 242 c +454 165 533 127 632 127 c +730 127 808 166 865 243 c +922 320 951 426 951 559 c +951 692 922 797 865 874 c +808 952 730 991 632 991 c + +632 1147 m +792 1147 918 1095 1009 991 c +1100 887 1146 743 1146 559 c +1146 376 1100 232 1009 127 c +918 23 792 -29 632 -29 c +471 -29 345 23 254 127 c +163 232 118 376 118 559 c +118 743 163 887 254 991 c +345 1095 471 1147 632 1147 c + +ce} _d +/uni01A2{1943 0 115 -29 1743 1520 sc +1541 0 m +1541 979 l +1541 1108 1523 1198 1486 1248 c +1449 1298 1390 1323 1309 1323 c +1309 182 l +1184 41 1016 -29 806 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c +882 1520 951 1511 1016 1493 c +1311 1493 l +1462 1493 1572 1452 1640 1371 c +1709 1290 1743 1159 1743 979 c +1743 0 l +1541 0 l + +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 746 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +924 135 1025 169 1110 238 c +1110 1286 l +1018 1333 917 1356 807 1356 c + +ce} _d +/uni01A3{1555 0 113 -426 1369 1147 sc +1185 -426 m +1185 714 l +1185 816 1172 883 1147 916 c +1122 948 1074 964 1004 964 c +1004 128 l +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c +694 1147 754 1138 809 1120 c +1025 1120 l +1146 1120 1233 1088 1288 1024 c +1342 960 1369 857 1369 714 c +1369 -426 l +1185 -426 l + +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +713 127 777 146 820 185 c +820 937 l +764 973 700 991 627 991 c + +ce} _d +/uni01A4{1335 0 -105 0 1265 1493 sc +503 1327 m +503 766 l +757 766 l +851 766 924 790 975 839 c +1026 888 1052 957 1052 1047 c +1052 1136 1026 1205 975 1254 c +924 1303 851 1327 757 1327 c +503 1327 l + +301 1493 m +757 1493 l +924 1493 1051 1455 1136 1379 c +1222 1304 1265 1193 1265 1047 c +1265 900 1222 788 1136 713 c +1051 638 924 600 757 600 c +503 600 l +503 0 l +301 0 l +301 1328 l +213 1328 149 1312 110 1280 c +71 1249 51 1198 51 1128 c +51 1079 l +-105 1079 l +-105 1149 l +-105 1270 -73 1357 -9 1411 c +55 1466 158 1493 301 1493 c + +ce} _d +/uni01A5{1300 0 185 -426 1188 1556 sc +371 168 m +371 -426 l +185 -426 l +185 1150 l +185 1293 212 1396 266 1460 c +321 1524 408 1556 529 1556 c +783 1556 l +783 1400 l +552 1400 l +482 1400 434 1384 409 1351 c +384 1319 371 1252 371 1150 c +371 950 l +410 1017 458 1066 517 1098 c +576 1131 647 1147 729 1147 c +865 1147 975 1093 1060 985 c +1145 877 1188 735 1188 559 c +1188 383 1145 241 1060 133 c +975 25 865 -29 729 -29 c +647 -29 576 -13 517 19 c +458 52 410 101 371 168 c + +997 559 m +997 694 969 800 913 877 c +858 954 781 993 684 993 c +587 993 510 954 454 877 c +399 800 371 694 371 559 c +371 424 399 317 454 240 c +510 163 587 125 684 125 c +781 125 858 163 913 240 c +969 317 997 424 997 559 c + +ce} _d +/uni01A6{1423 0 201 -264 1364 1493 sc +909 436 m +952 421 994 390 1035 342 c +1076 294 1118 228 1159 144 c +1364 -264 l +1147 -264 l +956 119 l +907 219 859 285 812 318 c +766 351 703 367 623 367 c +403 367 l +403 0 l +201 0 l +201 1493 l +403 1493 l +403 1229 l +657 1229 l +828 1229 955 1193 1039 1122 c +1123 1051 1165 943 1165 799 c +1165 705 1143 627 1099 565 c +1056 503 992 460 909 436 c + +403 1063 m +403 504 l +657 504 l +751 504 824 528 875 577 c +926 626 952 695 952 784 c +952 873 926 942 875 990 c +824 1039 752 1063 657 1063 c +403 1063 l + +ce} _d +/uni01A7{1300 0 114 -29 1165 1520 sc +204 1444 m +356 1495 508 1520 659 1520 c +810 1520 932 1482 1025 1406 c +1118 1330 1165 1230 1165 1107 c +1165 984 1131 891 1064 827 c +997 763 888 716 737 686 c +614 662 l +511 641 437 610 392 569 c +347 528 325 468 325 389 c +325 310 356 248 419 203 c +482 158 571 135 686 135 c +836 135 994 181 1159 274 c +1159 66 l +986 3 829 -29 686 -29 c +499 -29 356 8 259 83 c +162 158 114 267 114 412 c +114 533 150 630 221 702 c +293 775 404 825 555 854 c +677 879 l +788 900 863 927 903 960 c +942 994 962 1047 962 1119 c +962 1192 932 1249 873 1292 c +813 1335 724 1356 607 1356 c +490 1356 356 1320 204 1247 c +204 1444 l + +ce} _d +/uni01A8{1067 0 100 -29 956 1147 sc +160 1087 m +211 1107 266 1122 326 1132 c +386 1142 450 1147 518 1147 c +655 1147 761 1118 836 1061 c +911 1004 948 922 948 817 c +948 730 923 662 872 612 c +821 563 739 526 625 502 c +561 487 l +447 462 373 437 339 410 c +306 383 289 345 289 295 c +289 241 312 199 359 169 c +406 140 472 125 559 125 c +624 125 689 134 755 151 c +821 169 888 196 956 231 c +956 41 l +884 18 815 0 750 -11 c +685 -23 623 -29 563 -29 c +419 -29 306 1 223 62 c +141 123 100 205 100 309 c +100 400 127 471 182 522 c +237 573 330 613 461 641 c +524 655 l +623 677 688 700 721 724 c +754 749 770 782 770 825 c +770 881 747 923 701 951 c +656 979 587 993 496 993 c +436 993 378 986 322 973 c +266 960 212 940 160 913 c +160 1087 l + +ce} _d +/uni01A9{1294 0 201 0 1163 1493 sc +433 170 m +1163 170 l +1163 0 l +201 0 l +201 170 l +680 794 l +201 1323 l +201 1493 l +1145 1493 l +1145 1323 l +433 1323 l +912 798 l +433 170 l + +ce} _d +/uni01AA{688 0 -270 -426 727 1556 sc +375 1130 m +375 -89 l +375 -158 388 -206 413 -233 c +439 -260 485 -273 551 -273 c +727 -273 l +727 -426 l +553 -426 l +427 -426 335 -397 277 -340 c +219 -283 190 -193 190 -68 c +190 1130 l +0 1130 l +-180 1130 -270 1200 -270 1340 c +-270 1484 -169 1556 33 1556 c +154 1556 241 1524 296 1460 c +331 1417 355 1359 367 1285 c +558 1285 l +558 1130 l +375 1130 l + +180 1284 m +175 1313 166 1336 155 1352 c +133 1384 85 1400 12 1400 c +-71 1400 -113 1378 -115 1335 c +-117 1301 -78 1284 1 1284 c +180 1284 l + +ce} _d +/uni01AB{803 0 55 -426 754 1438 sc +375 1438 m +375 1120 l +754 1120 l +754 977 l +375 977 l +375 369 l +375 278 387 219 412 193 c +437 167 488 154 565 154 c +754 154 l +754 -20 l +754 -163 727 -266 672 -330 c +617 -394 530 -426 410 -426 c +340 -426 l +340 -270 l +388 -270 l +459 -270 507 -254 532 -222 c +557 -189 570 -122 570 -20 c +570 0 l +428 0 329 26 273 79 c +218 132 190 229 190 369 c +190 977 l +55 977 l +55 1120 l +190 1120 l +190 1438 l +375 1438 l + +ce} _d +/uni01AC{1251 0 24 0 1257 1493 sc +430 1493 m +1257 1493 l +1257 1323 l +727 1323 l +727 0 l +524 0 l +524 1323 l +430 1323 l +342 1323 278 1308 239 1278 c +200 1248 180 1198 180 1128 c +180 1079 l +24 1079 l +24 1149 l +24 1270 56 1357 120 1411 c +184 1466 287 1493 430 1493 c + +ce} _d +/uni01AD{803 0 55 0 754 1556 sc +375 1219 m +375 1120 l +754 1120 l +754 977 l +375 977 l +375 369 l +375 278 387 219 412 193 c +437 167 488 154 565 154 c +754 154 l +754 0 l +565 0 l +423 0 325 26 271 79 c +217 132 190 229 190 369 c +190 977 l +55 977 l +55 1120 l +190 1120 l +190 1198 l +190 1323 219 1413 277 1470 c +335 1527 427 1556 553 1556 c +727 1556 l +727 1403 l +551 1403 l +485 1403 439 1389 413 1362 c +388 1335 375 1288 375 1219 c + +ce} _d +/uni01AE{1251 0 -6 -410 1257 1493 sc +-6 1493 m +1257 1493 l +1257 1323 l +727 1323 l +727 104 l +727 -25 745 -115 782 -165 c +819 -215 882 -240 971 -240 c +1034 -240 l +1034 -410 l +956 -410 l +805 -410 695 -369 626 -288 c +558 -207 524 -76 524 104 c +524 1323 l +-6 1323 l +-6 1493 l + +ce} _d +/Uhorn{1757 0 173 -9 1631 1556 sc +173 1513 m +376 1513 l +376 606 l +376 446 405 331 463 260 c +521 190 615 155 745 155 c +874 155 968 190 1026 260 c +1084 331 1113 446 1113 606 c +1113 1513 l +1316 1513 l +1316 581 l +1316 386 1268 239 1171 140 c +1075 41 933 -9 745 -9 c +556 -9 414 41 317 140 c +221 239 173 386 173 581 c +173 1513 l + +1236 1291 m +1236 1410 l +1277 1380 1312 1358 1341 1343 c +1370 1329 1395 1322 1416 1322 c +1447 1322 1470 1331 1485 1349 c +1500 1368 1508 1395 1508 1431 c +1508 1452 1505 1473 1500 1494 c +1495 1515 1488 1535 1478 1556 c +1611 1556 l +1618 1531 1623 1507 1626 1484 c +1629 1461 1631 1440 1631 1420 c +1631 1339 1616 1279 1587 1240 c +1558 1202 1513 1183 1451 1183 c +1419 1183 1385 1192 1350 1209 c +1315 1227 1277 1254 1236 1291 c + +ce} _d +/uhorn{1298 0 176 -29 1385 1259 sc +990 994 m +990 1113 l +1031 1083 1066 1061 1095 1046 c +1124 1032 1149 1025 1170 1025 c +1201 1025 1224 1034 1239 1052 c +1254 1071 1262 1098 1262 1134 c +1262 1155 1259 1176 1254 1197 c +1249 1218 1242 1238 1232 1259 c +1365 1259 l +1372 1234 1377 1210 1380 1187 c +1383 1164 1385 1143 1385 1123 c +1385 1042 1370 982 1341 943 c +1312 905 1267 886 1205 886 c +1173 886 1139 895 1104 912 c +1069 930 1031 957 990 994 c + +176 442 m +176 1120 l +360 1120 l +360 449 l +360 343 381 263 422 210 c +463 157 525 131 608 131 c +707 131 786 163 843 226 c +901 289 930 376 930 485 c +930 1120 l +1114 1120 l +1114 0 l +930 0 l +930 172 l +885 104 833 53 774 20 c +715 -13 647 -29 569 -29 c +440 -29 343 11 276 91 c +209 171 176 288 176 442 c + +639 1147 m +639 1147 l + +ce} _d +/uni01B1{1565 0 78 -29 1487 1482 sc +1487 1304 m +1167 1304 l +1274 1210 1352 1114 1399 1015 c +1446 916 1470 802 1470 673 c +1470 467 1406 298 1277 167 c +1149 36 984 -29 782 -29 c +579 -29 413 37 285 168 c +158 299 94 471 94 683 c +94 806 118 917 166 1016 c +215 1115 292 1211 397 1304 c +78 1304 l +78 1482 l +678 1482 l +678 1304 l +559 1239 467 1152 400 1041 c +334 930 301 808 301 673 c +301 514 345 385 433 288 c +522 191 638 143 782 143 c +926 143 1042 191 1130 288 c +1218 385 1262 513 1262 673 c +1262 808 1229 930 1163 1041 c +1097 1152 1005 1239 887 1304 c +887 1482 l +1487 1482 l +1487 1304 l + +ce} _d +/uni01B2{1476 0 201 -31 1398 1493 sc +710 141 m +854 141 970 189 1058 286 c +1146 383 1190 511 1190 671 c +1190 806 1157 928 1091 1039 c +1048 1112 989 1177 916 1235 c +916 1303 l +1095 1302 l +1202 1208 1280 1112 1327 1013 c +1374 914 1398 800 1398 671 c +1398 465 1334 296 1206 165 c +1079 34 913 -31 710 -31 c +633 -29 l +478 -25 369 16 304 93 c +235 174 201 305 201 485 c +201 1493 l +403 1493 l +403 485 l +403 356 421 266 458 216 c +495 166 558 141 647 141 c +710 141 l + +ce} _d +/uni01B3{1523 0 -4 0 1520 1520 sc +1239 1351 m +1201 1351 1175 1346 1161 1337 c +1136 1321 1118 1305 1107 1288 c +727 711 l +727 0 l +524 0 l +524 711 l +-4 1493 l +213 1493 l +627 879 l +961 1384 l +1021 1475 1105 1520 1214 1520 c +1305 1520 1378 1489 1435 1428 c +1492 1367 1520 1300 1520 1227 c +1520 1096 l +1350 1096 l +1350 1217 l +1350 1253 1338 1284 1313 1311 c +1289 1338 1264 1351 1239 1351 c + +ce} _d +/uni01B4{1496 0 61 -426 1496 1147 sc +659 -104 m +607 -237 556 -324 507 -365 c +458 -406 392 -426 309 -426 c +162 -426 l +162 -272 l +270 -272 l +321 -272 360 -260 388 -236 c +416 -212 447 -155 481 -66 c +514 18 l +61 1120 l +256 1120 l +606 244 l +888 948 l +902 983 925 1017 957 1051 c +1016 1115 1090 1147 1180 1147 c +1267 1147 1342 1115 1403 1051 c +1465 988 1496 911 1496 822 c +1496 708 l +1318 708 l +1318 822 l +1318 861 1304 894 1277 922 c +1250 950 1218 964 1180 964 c +1142 964 1109 950 1082 922 c +1069 909 1059 894 1052 877 c +659 -104 l + +ce} _d +/uni01B5{1403 0 92 0 1311 1493 sc +115 1493 m +1288 1493 l +1288 1339 l +888 844 l +1169 844 l +1169 700 l +772 700 l +344 170 l +1311 170 l +1311 0 l +92 0 l +92 154 l +533 700 l +234 700 l +234 844 l +649 844 l +1036 1323 l +115 1323 l +115 1493 l + +ce} _d +/uni01B6{1075 0 88 0 987 1120 sc +113 1120 m +987 1120 l +987 952 l +736 660 l +930 660 l +930 516 l +612 516 l +295 147 l +987 147 l +987 0 l +88 0 l +88 168 l +387 516 l +175 516 l +175 660 l +511 660 l +780 973 l +113 973 l +113 1120 l + +ce} _d +/uni01B7{1364 0 160 -63 1272 1493 sc +680 107 m +808 107 905 132 971 182 c +1038 232 1071 305 1071 400 c +1071 489 1040 558 979 607 c +917 656 831 681 721 681 c +547 681 l +547 833 l +932 1323 l +160 1323 l +160 1493 l +1184 1493 l +1184 1339 l +773 849 l +844 849 922 830 1007 793 c +1072 765 1134 715 1191 642 c +1245 573 1272 492 1272 400 c +1272 253 1221 139 1120 58 c +1019 -23 875 -63 688 -63 c +609 -63 527 -57 444 -44 c +360 -32 273 -14 184 11 c +184 206 l +255 173 332 149 417 132 c +501 115 589 107 680 107 c + +ce} _d +/uni01B8{1364 0 92 -63 1204 1493 sc +684 107 m +775 107 863 115 947 132 c +1032 149 1109 173 1180 206 c +1180 11 l +1091 -14 1004 -32 920 -44 c +837 -57 755 -63 676 -63 c +489 -63 345 -23 244 58 c +143 139 92 253 92 400 c +92 492 119 573 173 642 c +230 715 292 765 357 793 c +442 830 520 849 591 849 c +180 1339 l +180 1493 l +1204 1493 l +1204 1323 l +432 1323 l +817 833 l +817 681 l +643 681 l +533 681 447 656 385 607 c +324 558 293 489 293 400 c +293 305 326 232 393 182 c +459 132 556 107 684 107 c + +ce} _d +/uni01B9{1183 0 104 -436 1087 1120 sc +603 476 m +192 952 l +192 1120 l +1066 1120 l +1066 973 l +399 973 l +829 474 l +829 308 l +655 308 l +545 308 459 283 397 234 c +336 184 305 115 305 27 c +305 -68 338 -141 405 -191 c +471 -241 567 -266 694 -266 c +767 -266 836 -258 903 -241 c +970 -224 1031 -200 1087 -167 c +1087 -362 l +1016 -387 948 -405 881 -418 c +815 -430 751 -436 688 -436 c +501 -436 357 -396 256 -315 c +155 -234 104 -120 104 27 c +104 119 131 200 185 269 c +242 342 304 392 369 420 c +454 457 532 476 603 476 c + +ce} _d +/uni01BA{1075 0 113 -426 1000 1120 sc +639 -274 m +695 -274 749 -267 800 -253 c +853 -239 906 -217 960 -188 c +960 -367 l +902 -388 846 -403 793 -412 c +736 -421 675 -426 610 -426 c +290 -426 130 -332 130 -145 c +130 14 265 111 536 146 c +725 171 820 216 820 281 c +820 364 742 405 585 405 c +585 405 488 405 295 405 c +780 973 l +113 973 l +113 1120 l +987 1120 l +987 952 l +633 540 l +878 540 1000 464 1000 311 c +1000 127 845 19 536 -14 c +385 -30 310 -70 310 -135 c +310 -228 420 -274 639 -274 c + +ce} _d +/uni01BB{1303 0 150 0 1098 1520 sc +393 170 m +1098 170 l +1098 0 l +150 0 l +150 170 l +464 490 l +579 607 l +234 607 l +234 751 l +716 751 l +779 824 823 884 848 932 c +874 983 887 1032 887 1081 c +887 1160 859 1225 804 1275 c +748 1325 675 1350 586 1350 c +523 1350 456 1339 386 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 1079 975 1056 920 c +1035 871 1000 815 951 751 c +1055 751 l +1055 607 l +819 607 l +771 558 l +393 170 l + +ce} _d +/uni01BC{1364 0 93 -63 1273 1493 sc +294 400 m +294 205 424 107 683 107 c +942 107 1072 205 1072 400 c +1072 489 1041 558 979 607 c +918 656 832 681 722 681 c +201 681 l +201 1493 l +1130 1493 l +1130 1323 l +403 1323 l +403 848 l +774 849 l +945 850 1084 781 1192 642 c +1246 573 1273 490 1273 394 c +1273 298 1253 221 1214 164 c +1186 123 l +1173 104 1151 82 1121 58 c +1020 -23 874 -63 683 -63 c +492 -63 346 -23 245 58 c +144 139 93 253 93 400 c +294 400 l + +ce} _d +/uni01BD{1183 0 104 -436 1087 1120 sc +104 -167 m +217 -233 343 -266 480 -266 c +751 -266 886 -168 886 27 c +886 116 855 185 793 234 c +732 283 646 308 536 308 c +183 308 l +183 1120 l +976 1120 l +976 950 l +367 950 l +367 476 l +588 476 l +658 476 731 459 807 426 c +883 393 949 342 1004 271 c +1059 200 1087 117 1087 21 c +1087 -75 1067 -152 1028 -209 c +1000 -250 l +987 -269 965 -291 935 -315 c +834 -396 690 -436 503 -436 c +378 -436 245 -411 104 -362 c +104 -167 l + +ce} _d +/uni01BE{1045 0 88 -29 933 1438 sc +545 998 m +543 873 l +656 853 750 803 825 724 c +897 647 933 552 933 439 c +933 315 896 211 823 128 c +732 23 594 -29 411 -29 c +354 -29 299 -23 245 -11 c +191 0 139 18 88 41 c +88 213 l +137 186 189 165 245 149 c +297 134 350 127 403 127 c +522 127 615 165 681 241 c +719 284 738 350 739 439 c +739 504 720 562 681 613 c +624 689 531 727 403 727 c +341 727 l +343 998 l +114 998 l +114 1162 l +343 1162 l +343 1438 l +545 1438 l +545 1162 l +776 1162 l +776 998 l +545 998 l + +ce} _d +/uni01BF{1300 0 186 -426 1188 1147 sc +371 -122 m +371 -426 l +186 -426 l +186 1120 l +371 1120 l +371 950 l +406 994 468 1043 558 1098 c +612 1131 709 1147 849 1147 c +972 1147 1059 1110 1110 1035 c +1162 960 1188 871 1188 769 c +1188 486 916 189 371 -122 c + +371 60 m +788 327 997 543 997 709 c +997 798 978 864 940 908 c +903 951 844 973 764 973 c +617 973 486 893 371 734 c +371 60 l + +ce} _d +/uni01C0{604 0 201 -426 403 1493 sc +201 1493 m +403 1493 l +403 -426 l +201 -426 l +201 1493 l + +ce} _d +/uni01C1{1008 0 201 -426 807 1493 sc +605 1493 m +807 1493 l +807 -426 l +605 -426 l +605 1493 l + +201 1493 m +403 1493 l +403 -426 l +201 -426 l +201 1493 l + +ce} _d +/uni01C2{940 0 20 -426 924 1493 sc +371 1493 m +573 1493 l +573 876 l +924 876 l +924 708 l +573 708 l +573 468 l +924 468 l +924 298 l +573 298 l +573 -426 l +371 -426 l +371 298 l +20 298 l +20 468 l +371 468 l +371 708 l +20 708 l +20 876 l +371 876 l +371 1493 l + +ce} _d +/uni01C3{605 0 201 0 404 1493 sc +201 254 m +404 254 l +404 0 l +201 0 l +201 254 l + +201 1493 m +404 1493 l +404 838 l +384 481 l +222 481 l +201 838 l +201 1493 l + +ce} _d +/uni01C4{2912 0 201 0 2768 1901 sc +1572 1493 m +2745 1493 l +2745 1339 l +1801 170 l +2768 170 l +2768 0 l +1549 0 l +1549 154 l +2493 1323 l +1572 1323 l +1572 1493 l + +2065 1635 m +1854 1901 l +1993 1901 l +2159 1723 l +2325 1901 l +2464 1901 l +2253 1635 l +2065 1635 l + +403 1327 m +403 166 l +647 166 l +853 166 1004 213 1099 306 c +1195 399 1243 547 1243 748 c +1243 948 1195 1094 1099 1187 c +1004 1280 853 1327 647 1327 c +403 1327 l + +201 1493 m +616 1493 l +905 1493 1118 1433 1253 1312 c +1388 1192 1456 1004 1456 748 c +1456 491 1388 302 1252 181 c +1116 60 904 0 616 0 c +201 0 l +201 1493 l + +ce} _d +/uni01C5{2660 0 201 0 2480 1638 sc +1606 1120 m +2480 1120 l +2480 952 l +1788 147 l +2480 147 l +2480 0 l +1581 0 l +1581 168 l +2273 973 l +1606 973 l +1606 1120 l + +1958 1262 m +1713 1638 l +1852 1638 l +2032 1393 l +2212 1638 l +2351 1638 l +2106 1262 l +1958 1262 l + +403 1327 m +403 166 l +647 166 l +853 166 1004 213 1099 306 c +1195 399 1243 547 1243 748 c +1243 948 1195 1094 1099 1187 c +1004 1280 853 1327 647 1327 c +403 1327 l + +201 1493 m +616 1493 l +905 1493 1118 1433 1253 1312 c +1388 1192 1456 1004 1456 748 c +1456 491 1388 302 1252 181 c +1116 60 904 0 616 0 c +201 0 l +201 1493 l + +ce} _d +/uni01C6{2364 0 113 -29 2193 1638 sc +1319 1120 m +2193 1120 l +2193 952 l +1501 147 l +2193 147 l +2193 0 l +1294 0 l +1294 168 l +1986 973 l +1319 973 l +1319 1120 l + +1671 1262 m +1426 1638 l +1565 1638 l +1745 1393 l +1925 1638 l +2064 1638 l +1819 1262 l +1671 1262 l + +930 950 m +930 1556 l +1114 1556 l +1114 0 l +930 0 l +930 168 l +891 101 842 52 783 19 c +724 -13 654 -29 571 -29 c +436 -29 325 25 240 133 c +155 241 113 383 113 559 c +113 735 155 877 240 985 c +325 1093 436 1147 571 1147 c +654 1147 724 1131 783 1098 c +842 1066 891 1017 930 950 c + +303 559 m +303 424 331 317 386 240 c +442 163 519 125 616 125 c +713 125 790 163 846 240 c +902 317 930 424 930 559 c +930 694 902 800 846 877 c +790 954 713 993 616 993 c +519 993 442 954 386 877 c +331 800 303 694 303 559 c + +ce} _d +/uni01C7{1711 0 201 -410 1572 1493 sc +1370 1493 m +1572 1493 l +1572 104 l +1572 -76 1538 -207 1469 -288 c +1401 -369 1291 -410 1140 -410 c +1063 -410 l +1063 -240 l +1126 -240 l +1215 -240 1278 -215 1315 -165 c +1352 -115 1370 -25 1370 104 c +1370 1493 l + +201 1493 m +403 1493 l +403 170 l +1130 170 l +1130 0 l +201 0 l +201 1493 l + +ce} _d +/uni01C8{1611 0 201 -426 1502 1556 sc +1318 1120 m +1502 1120 l +1502 -20 l +1502 -163 1475 -266 1420 -330 c +1366 -394 1279 -426 1158 -426 c +1088 -426 l +1088 -270 l +1137 -270 l +1207 -270 1255 -254 1280 -221 c +1305 -189 1318 -122 1318 -20 c +1318 1120 l + +1318 1556 m +1502 1556 l +1502 1323 l +1318 1323 l +1318 1556 l + +201 1493 m +403 1493 l +403 170 l +1130 170 l +1130 0 l +201 0 l +201 1493 l + +ce} _d +/uni01C9{935 0 193 -426 751 1556 sc +567 1120 m +751 1120 l +751 -20 l +751 -163 724 -266 669 -330 c +615 -394 528 -426 407 -426 c +337 -426 l +337 -270 l +386 -270 l +456 -270 504 -254 529 -221 c +554 -189 567 -122 567 -20 c +567 1120 l + +567 1556 m +751 1556 l +751 1323 l +567 1323 l +567 1556 l + +193 1556 m +377 1556 l +377 0 l +193 0 l +193 1556 l + +ce} _d +/uni01CA{1907 0 201 -410 1778 1493 sc +1576 1493 m +1778 1493 l +1778 104 l +1778 -76 1744 -207 1675 -288 c +1607 -369 1497 -410 1346 -410 c +1269 -410 l +1269 -240 l +1332 -240 l +1421 -240 1484 -215 1521 -165 c +1558 -115 1576 -25 1576 104 c +1576 1493 l + +201 1493 m +473 1493 l +1135 244 l +1135 1493 l +1331 1493 l +1331 0 l +1059 0 l +397 1249 l +397 0 l +201 0 l +201 1493 l + +ce} _d +/uni01CB{1892 0 201 -426 1719 1556 sc +1535 1120 m +1719 1120 l +1719 -20 l +1719 -163 1692 -266 1637 -330 c +1583 -394 1496 -426 1375 -426 c +1305 -426 l +1305 -270 l +1354 -270 l +1424 -270 1472 -254 1497 -221 c +1522 -189 1535 -122 1535 -20 c +1535 1120 l + +1535 1556 m +1719 1556 l +1719 1323 l +1535 1323 l +1535 1556 l + +201 1493 m +473 1493 l +1135 244 l +1135 1493 l +1331 1493 l +1331 0 l +1059 0 l +397 1249 l +397 0 l +201 0 l +201 1493 l + +ce} _d +/uni01CC{1633 0 186 -426 1502 1556 sc +1318 1120 m +1502 1120 l +1502 -20 l +1502 -163 1475 -266 1420 -330 c +1366 -394 1279 -426 1158 -426 c +1088 -426 l +1088 -270 l +1137 -270 l +1207 -270 1255 -254 1280 -221 c +1305 -189 1318 -122 1318 -20 c +1318 1120 l + +1318 1556 m +1502 1556 l +1502 1323 l +1318 1323 l +1318 1556 l + +1124 676 m +1124 0 l +940 0 l +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1027 c +1091 948 1124 831 1124 676 c + +ce} _d +/uni01CD{1401 0 16 0 1384 1901 sc +700 1294 m +426 551 l +975 551 l +700 1294 l + +586 1493 m +815 1493 l +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +586 1493 l + +608 1635 m +397 1901 l +536 1901 l +702 1723 l +868 1901 l +1007 1901 l +796 1635 l +608 1635 l + +ce} _d +/uni01CE{1255 0 123 -29 1069 1638 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +528 1262 m +283 1638 l +422 1638 l +602 1393 l +782 1638 l +921 1638 l +676 1262 l +528 1262 l + +ce} _d +/uni01CF{604 0 -2 0 608 1901 sc +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +209 1635 m +-2 1901 l +137 1901 l +303 1723 l +469 1901 l +608 1901 l +397 1635 l +209 1635 l + +ce} _d +/uni01D0{569 0 -32 0 606 1638 sc +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +285 1147 m +285 1147 l + +213 1262 m +-32 1638 l +107 1638 l +287 1393 l +467 1638 l +606 1638 l +361 1262 l +213 1262 l + +ce} _d +/uni01D1{1612 0 115 -29 1497 1901 sc +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +713 1635 m +502 1901 l +641 1901 l +807 1723 l +973 1901 l +1112 1901 l +901 1635 l +713 1635 l + +ce} _d +/uni01D2{1253 0 113 -29 1141 1638 sc +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +556 1262 m +311 1638 l +450 1638 l +630 1393 l +810 1638 l +949 1638 l +704 1262 l +556 1262 l + +ce} _d +/uni01D3{1499 0 178 -29 1321 1901 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +664 1635 m +453 1901 l +592 1901 l +758 1723 l +924 1901 l +1063 1901 l +852 1635 l +664 1635 l + +ce} _d +/uni01D4{1298 0 174 -29 1112 1638 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +556 1262 m +311 1638 l +450 1638 l +630 1393 l +810 1638 l +949 1638 l +704 1262 l +556 1262 l + +ce} _d +/uni01D5{1499 0 178 -29 1321 2099 sc +450 2099 m +1048 2099 l +1048 1951 l +450 1951 l +450 2099 l + +842 1838 m +1045 1838 l +1045 1635 l +842 1635 l +842 1838 l + +451 1838 m +654 1838 l +654 1635 l +451 1635 l +451 1838 l + +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +ce} _d +/uni01D6{1298 0 174 -29 1112 1841 sc +336 1841 m +934 1841 l +934 1693 l +336 1693 l +336 1841 l + +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +729 1552 m +932 1552 l +932 1350 l +729 1350 l +729 1552 l + +338 1552 m +541 1552 l +541 1350 l +338 1350 l +338 1552 l + +ce} _d +/uni01D7{1499 0 178 -29 1321 2138 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +861 2138 m +1046 2138 l +818 1874 l +665 1874 l +861 2138 l + +848 1838 m +1051 1838 l +1051 1635 l +848 1635 l +848 1838 l + +457 1838 m +660 1838 l +660 1635 l +457 1635 l +457 1838 l + +ce} _d +/uni01D8{1298 0 174 -29 1112 1826 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +741 1826 m +926 1826 l +698 1562 l +545 1562 l +741 1826 l + +728 1526 m +931 1526 l +931 1323 l +728 1323 l +728 1526 l + +337 1526 m +540 1526 l +540 1323 l +337 1323 l +337 1526 l + +ce} _d +/uni01D9{1499 0 178 -29 1321 2138 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +654 1872 m +443 2138 l +582 2138 l +748 1960 l +914 2138 l +1053 2138 l +842 1872 l +654 1872 l + +842 1838 m +1045 1838 l +1045 1635 l +842 1635 l +842 1838 l + +451 1838 m +654 1838 l +654 1635 l +451 1635 l +451 1838 l + +ce} _d +/uni01DA{1298 0 174 -29 1112 1826 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +546 1560 m +335 1826 l +474 1826 l +640 1648 l +806 1826 l +945 1826 l +734 1560 l +546 1560 l + +734 1526 m +937 1526 l +937 1323 l +734 1323 l +734 1526 l + +343 1526 m +546 1526 l +546 1323 l +343 1323 l +343 1526 l + +ce} _d +/uni01DB{1499 0 178 -29 1321 2144 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +643 2144 m +839 1880 l +686 1880 l +456 2144 l +643 2144 l + +842 1844 m +1045 1844 l +1045 1641 l +842 1641 l +842 1844 l + +451 1844 m +654 1844 l +654 1641 l +451 1641 l +451 1844 l + +ce} _d +/uni01DC{1298 0 174 -29 1112 1826 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +529 1826 m +725 1562 l +572 1562 l +342 1826 l +529 1826 l + +728 1526 m +931 1526 l +931 1323 l +728 1323 l +728 1526 l + +337 1526 m +540 1526 l +540 1323 l +337 1323 l +337 1526 l + +ce} _d +/uni01DD{1260 0 113 -29 1151 1147 sc +113 512 m +113 602 l +959 602 l +951 729 913 825 844 891 c +776 958 681 991 559 991 c +488 991 420 982 353 965 c +287 948 221 922 156 887 c +156 1061 l +222 1089 290 1110 359 1125 c +428 1140 499 1147 570 1147 c +749 1147 890 1095 994 991 c +1099 887 1151 746 1151 569 c +1151 386 1101 240 1002 132 c +903 25 770 -29 602 -29 c +451 -29 332 19 244 116 c +157 213 113 345 113 512 c + +297 458 m +298 357 326 277 381 217 c +436 157 509 127 600 127 c +703 127 785 156 846 214 c +908 272 944 354 953 459 c +297 458 l + +ce} _d +/uni01DE{1401 0 16 0 1384 2099 sc +700 1294 m +426 551 l +975 551 l +700 1294 l + +586 1493 m +815 1493 l +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +586 1493 l + +402 2099 m +1000 2099 l +1000 1951 l +402 1951 l +402 2099 l + +794 1838 m +997 1838 l +997 1635 l +794 1635 l +794 1838 l + +403 1838 m +606 1838 l +606 1635 l +403 1635 l +403 1838 l + +ce} _d +/uni01DF{1255 0 123 -29 1069 1841 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +688 1552 m +891 1552 l +891 1350 l +688 1350 l +688 1552 l + +297 1552 m +500 1552 l +500 1350 l +297 1350 l +297 1552 l + +295 1841 m +893 1841 l +893 1693 l +295 1693 l +295 1841 l + +ce} _d +/uni01E0{1401 0 16 0 1384 2099 sc +700 1294 m +426 551 l +975 551 l +700 1294 l + +586 1493 m +815 1493 l +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +586 1493 l + +598 1835 m +802 1835 l +802 1630 l +598 1630 l +598 1835 l + +402 2099 m +1000 2099 l +1000 1951 l +402 1951 l +402 2099 l + +ce} _d +/uni01E1{1255 0 123 -29 1069 1780 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +489 1516 m +693 1516 l +693 1311 l +489 1311 l +489 1516 l + +293 1780 m +891 1780 l +891 1632 l +293 1632 l +293 1780 l + +ce} _d +/uni01E2{1995 0 8 0 1864 1844 sc +940 1844 m +1538 1844 l +1538 1696 l +940 1696 l +940 1844 l + +1845 1493 m +1845 1323 l +1104 1323 l +1104 881 l +1815 881 l +1815 711 l +1104 711 l +1104 170 l +1864 170 l +1864 0 l +901 0 l +901 383 l +373 383 l +213 0 l +8 0 l +633 1493 l +1845 1493 l + +772 1335 m +442 551 l +901 551 l +901 1335 l +772 1335 l + +ce} _d +/uni01E3{2011 0 123 -29 1903 1522 sc +701 1522 m +1299 1522 l +1299 1374 l +701 1374 l +701 1522 l + +1718 660 m +1717 761 1689 841 1634 901 c +1579 961 1506 991 1415 991 c +1313 991 1231 962 1169 904 c +1108 846 1072 764 1063 659 c +1718 660 l + +995 963 m +1044 1023 1104 1069 1175 1100 c +1246 1131 1325 1147 1413 1147 c +1564 1147 1683 1098 1771 1001 c +1859 904 1903 773 1903 606 c +1903 516 l +1057 516 l +1065 389 1103 292 1171 225 c +1239 158 1334 125 1456 125 c +1525 125 1593 134 1660 151 c +1727 169 1793 196 1860 231 c +1860 57 l +1793 29 1725 8 1656 -7 c +1587 -22 1517 -29 1446 -29 c +1335 -29 1238 -9 1155 31 c +1072 72 1005 132 954 211 c +905 131 845 71 773 31 c +701 -9 617 -29 522 -29 c +396 -29 298 2 228 64 c +158 127 123 214 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +681 1147 763 1131 834 1099 c +905 1067 959 1022 995 963 c + +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +ce} _d +/uni01E4{1587 0 115 -29 1540 1520 sc +1419 780 m +1419 482 l +1540 482 l +1540 394 l +1419 394 l +1419 139 l +1341 84 1255 42 1161 13 c +1067 -15 967 -29 860 -29 c +627 -29 444 39 312 175 c +181 312 115 502 115 745 c +115 989 181 1179 312 1315 c +444 1452 627 1520 860 1520 c +957 1520 1050 1508 1137 1484 c +1225 1460 1306 1425 1380 1378 c +1380 1163 l +1305 1226 1226 1274 1142 1306 c +1058 1338 970 1354 877 1354 c +694 1354 557 1303 465 1201 c +374 1099 328 947 328 745 c +328 544 374 392 465 290 c +557 188 694 137 877 137 c +948 137 1012 143 1068 155 c +1124 168 1174 187 1219 213 c +1219 394 l +966 394 l +966 482 l +1219 482 l +1219 614 l +889 614 l +889 780 l +1419 780 l + +ce} _d +/uni01E5{1300 0 113 -426 1274 1147 sc +930 573 m +930 706 902 810 847 883 c +792 956 715 993 616 993 c +517 993 440 956 385 883 c +330 810 303 706 303 573 c +303 440 330 337 385 264 c +440 191 517 154 616 154 c +715 154 792 191 847 264 c +902 337 930 440 930 573 c + +1114 139 m +1114 66 1108 -0 1095 -59 c +1274 -59 l +1274 -129 l +1076 -129 l +1055 -191 1026 -243 987 -286 c +902 -379 773 -426 598 -426 c +533 -426 472 -421 415 -411 c +358 -402 302 -387 248 -367 c +248 -188 l +302 -217 355 -239 408 -253 c +461 -267 514 -274 569 -274 c +690 -274 780 -242 840 -179 c +854 -164 867 -147 878 -128 c +242 -128 l +242 -59 l +908 -59 l +923 -12 930 43 930 106 c +930 197 l +892 131 843 82 784 49 c +725 16 654 0 571 0 c +434 0 323 52 239 157 c +155 262 113 400 113 573 c +113 746 155 885 239 990 c +323 1095 434 1147 571 1147 c +654 1147 725 1131 784 1098 c +843 1065 892 1016 930 950 c +930 1120 l +1114 1120 l +1114 139 l + +ce} _d +/Gcaron{1587 0 115 -29 1419 1901 sc +1219 213 m +1219 614 l +889 614 l +889 780 l +1419 780 l +1419 139 l +1341 84 1255 42 1161 13 c +1067 -15 967 -29 860 -29 c +627 -29 444 39 312 175 c +181 312 115 502 115 745 c +115 989 181 1179 312 1315 c +444 1452 627 1520 860 1520 c +957 1520 1050 1508 1137 1484 c +1225 1460 1306 1425 1380 1378 c +1380 1163 l +1305 1226 1226 1274 1142 1306 c +1058 1338 970 1354 877 1354 c +694 1354 557 1303 465 1201 c +374 1099 328 947 328 745 c +328 544 374 392 465 290 c +557 188 694 137 877 137 c +948 137 1012 143 1068 155 c +1124 168 1174 187 1219 213 c + +748 1635 m +537 1901 l +676 1901 l +842 1723 l +1008 1901 l +1147 1901 l +936 1635 l +748 1635 l + +ce} _d +/gcaron{1300 0 113 -426 1114 1635 sc +512 1259 m +267 1635 l +406 1635 l +586 1390 l +766 1635 l +905 1635 l +660 1259 l +512 1259 l + +930 573 m +930 706 902 810 847 883 c +792 956 715 993 616 993 c +517 993 440 956 385 883 c +330 810 303 706 303 573 c +303 440 330 337 385 264 c +440 191 517 154 616 154 c +715 154 792 191 847 264 c +902 337 930 440 930 573 c + +1114 139 m +1114 -52 1072 -193 987 -286 c +902 -379 773 -426 598 -426 c +533 -426 472 -421 415 -411 c +358 -402 302 -387 248 -367 c +248 -188 l +302 -217 355 -239 408 -253 c +461 -267 514 -274 569 -274 c +690 -274 780 -242 840 -179 c +900 -116 930 -21 930 106 c +930 197 l +892 131 843 82 784 49 c +725 16 654 0 571 0 c +434 0 323 52 239 157 c +155 262 113 400 113 573 c +113 746 155 885 239 990 c +323 1095 434 1147 571 1147 c +654 1147 725 1131 784 1098 c +843 1065 892 1016 930 950 c +930 1120 l +1114 1120 l +1114 139 l + +ce} _d +/uni01E8{1343 0 201 0 1386 1901 sc +580 1635 m +369 1901 l +508 1901 l +674 1723 l +840 1901 l +979 1901 l +768 1635 l +580 1635 l + +201 1493 m +403 1493 l +403 862 l +1073 1493 l +1333 1493 l +592 797 l +1386 0 l +1120 0 l +403 719 l +403 0 l +201 0 l +201 1493 l + +ce} _d +/uni01E9{1186 0 -23 0 1180 1901 sc +186 1556 m +371 1556 l +371 637 l +920 1120 l +1155 1120 l +561 596 l +1180 0 l +940 0 l +371 547 l +371 0 l +186 0 l +186 1556 l + +188 1635 m +-23 1901 l +116 1901 l +282 1723 l +448 1901 l +587 1901 l +376 1635 l +188 1635 l + +ce} _d +/uni01EA{1612 0 115 -395 1497 1520 sc +748 0 m +867 0 l +837 -41 815 -76 800 -105 c +786 -134 779 -159 779 -180 c +779 -211 788 -234 806 -249 c +825 -264 852 -272 888 -272 c +909 -272 930 -269 951 -264 c +972 -259 992 -252 1013 -242 c +1013 -375 l +988 -382 964 -387 941 -390 c +918 -393 897 -395 877 -395 c +796 -395 736 -380 697 -351 c +659 -322 640 -277 640 -215 c +640 -183 649 -149 666 -114 c +684 -79 711 -41 748 0 c + +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +ce} _d +/uni01EB{1253 0 113 -395 1141 1147 sc +568 0 m +687 0 l +657 -41 635 -76 620 -105 c +606 -134 599 -159 599 -180 c +599 -211 608 -234 626 -249 c +645 -264 672 -272 708 -272 c +729 -272 750 -269 771 -264 c +792 -259 812 -252 833 -242 c +833 -375 l +808 -382 784 -387 761 -390 c +738 -393 717 -395 697 -395 c +616 -395 556 -380 517 -351 c +479 -322 460 -277 460 -215 c +460 -183 469 -149 486 -114 c +504 -79 531 -41 568 0 c + +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +ce} _d +/uni01EC{1612 0 115 -395 1497 1841 sc +508 1841 m +1106 1841 l +1106 1693 l +508 1693 l +508 1841 l + +748 0 m +867 0 l +837 -41 815 -76 800 -105 c +786 -134 779 -159 779 -180 c +779 -211 788 -234 806 -249 c +825 -264 852 -272 888 -272 c +909 -272 930 -269 951 -264 c +972 -259 992 -252 1013 -242 c +1013 -375 l +988 -382 964 -387 941 -390 c +918 -393 897 -395 877 -395 c +796 -395 736 -380 697 -351 c +659 -322 640 -277 640 -215 c +640 -183 649 -149 666 -114 c +684 -79 711 -41 748 0 c + +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +ce} _d +/uni01ED{1253 0 113 -395 1141 1525 sc +328 1525 m +926 1525 l +926 1377 l +328 1377 l +328 1525 l + +568 0 m +687 0 l +657 -41 635 -76 620 -105 c +606 -134 599 -159 599 -180 c +599 -211 608 -234 626 -249 c +645 -264 672 -272 708 -272 c +729 -272 750 -269 771 -264 c +792 -259 812 -252 833 -242 c +833 -375 l +808 -382 784 -387 761 -390 c +738 -393 717 -395 697 -395 c +616 -395 556 -380 517 -351 c +479 -322 460 -277 460 -215 c +460 -183 469 -149 486 -114 c +504 -79 531 -41 568 0 c + +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +ce} _d +/uni01EE{1364 0 160 -63 1272 1901 sc +608 1635 m +397 1901 l +536 1901 l +702 1723 l +868 1901 l +1007 1901 l +796 1635 l +608 1635 l + +680 107 m +808 107 905 132 971 182 c +1038 232 1071 305 1071 400 c +1071 489 1040 558 979 607 c +917 656 831 681 721 681 c +547 681 l +547 833 l +932 1323 l +160 1323 l +160 1493 l +1184 1493 l +1184 1339 l +773 849 l +844 849 922 830 1007 793 c +1072 765 1134 715 1191 642 c +1245 573 1272 492 1272 400 c +1272 253 1221 139 1120 58 c +1019 -23 875 -63 688 -63 c +609 -63 527 -57 444 -44 c +360 -32 273 -14 184 11 c +184 206 l +255 173 332 149 417 132 c +501 115 589 107 680 107 c + +ce} _d +/uni01EF{1183 0 88 -436 1071 1638 sc +465 1262 m +220 1638 l +359 1638 l +539 1393 l +719 1638 l +858 1638 l +613 1262 l +465 1262 l + +572 476 m +643 476 721 457 806 420 c +871 392 933 342 990 269 c +1044 200 1071 119 1071 27 c +1071 -120 1020 -234 919 -315 c +818 -396 674 -436 487 -436 c +424 -436 360 -430 294 -418 c +227 -405 159 -387 88 -362 c +88 -167 l +144 -200 205 -224 272 -241 c +339 -258 408 -266 481 -266 c +608 -266 704 -241 770 -191 c +837 -141 870 -68 870 27 c +870 115 839 184 778 234 c +716 283 630 308 520 308 c +346 308 l +346 474 l +776 973 l +109 973 l +109 1120 l +983 1120 l +983 952 l +572 476 l + +ce} _d +/uni01F0{569 0 -37 -426 612 1638 sc +219 1262 m +-26 1638 l +113 1638 l +293 1393 l +473 1638 l +612 1638 l +367 1262 l +219 1262 l + +193 1120 m +377 1120 l +377 -20 l +377 -163 350 -266 295 -330 c +241 -394 154 -426 33 -426 c +-37 -426 l +-37 -270 l +12 -270 l +82 -270 130 -254 155 -221 c +180 -189 193 -122 193 -20 c +193 1120 l + +ce} _d +/uni01F1{2912 0 201 0 2768 1493 sc +1572 1493 m +2745 1493 l +2745 1339 l +1801 170 l +2768 170 l +2768 0 l +1549 0 l +1549 154 l +2493 1323 l +1572 1323 l +1572 1493 l + +403 1327 m +403 166 l +647 166 l +853 166 1004 213 1099 306 c +1195 399 1243 547 1243 748 c +1243 948 1195 1094 1099 1187 c +1004 1280 853 1327 647 1327 c +403 1327 l + +201 1493 m +616 1493 l +905 1493 1118 1433 1253 1312 c +1388 1192 1456 1004 1456 748 c +1456 491 1388 302 1252 181 c +1116 60 904 0 616 0 c +201 0 l +201 1493 l + +ce} _d +/uni01F2{2660 0 201 0 2480 1493 sc +1606 1120 m +2480 1120 l +2480 952 l +1788 147 l +2480 147 l +2480 0 l +1581 0 l +1581 168 l +2273 973 l +1606 973 l +1606 1120 l + +403 1327 m +403 166 l +647 166 l +853 166 1004 213 1099 306 c +1195 399 1243 547 1243 748 c +1243 948 1195 1094 1099 1187 c +1004 1280 853 1327 647 1327 c +403 1327 l + +201 1493 m +616 1493 l +905 1493 1118 1433 1253 1312 c +1388 1192 1456 1004 1456 748 c +1456 491 1388 302 1252 181 c +1116 60 904 0 616 0 c +201 0 l +201 1493 l + +ce} _d +/uni01F3{2364 0 113 -29 2193 1556 sc +1319 1120 m +2193 1120 l +2193 952 l +1501 147 l +2193 147 l +2193 0 l +1294 0 l +1294 168 l +1986 973 l +1319 973 l +1319 1120 l + +930 950 m +930 1556 l +1114 1556 l +1114 0 l +930 0 l +930 168 l +891 101 842 52 783 19 c +724 -13 654 -29 571 -29 c +436 -29 325 25 240 133 c +155 241 113 383 113 559 c +113 735 155 877 240 985 c +325 1093 436 1147 571 1147 c +654 1147 724 1131 783 1098 c +842 1066 891 1017 930 950 c + +303 559 m +303 424 331 317 386 240 c +442 163 519 125 616 125 c +713 125 790 163 846 240 c +902 317 930 424 930 559 c +930 694 902 800 846 877 c +790 954 713 993 616 993 c +519 993 442 954 386 877 c +331 800 303 694 303 559 c + +ce} _d +/uni01F4{1587 0 115 -29 1419 1900 sc +850 1900 m +1035 1900 l +807 1636 l +654 1636 l +850 1900 l + +1219 213 m +1219 614 l +889 614 l +889 780 l +1419 780 l +1419 139 l +1341 84 1255 42 1161 13 c +1067 -15 967 -29 860 -29 c +627 -29 444 39 312 175 c +181 312 115 502 115 745 c +115 989 181 1179 312 1315 c +444 1452 627 1520 860 1520 c +957 1520 1050 1508 1137 1484 c +1225 1460 1306 1425 1380 1378 c +1380 1163 l +1305 1226 1226 1274 1142 1306 c +1058 1338 970 1354 877 1354 c +694 1354 557 1303 465 1201 c +374 1099 328 947 328 745 c +328 544 374 392 465 290 c +557 188 694 137 877 137 c +948 137 1012 143 1068 155 c +1124 168 1174 187 1219 213 c + +ce} _d +/uni01F5{1300 0 113 -426 1114 1635 sc +930 573 m +930 706 902 810 847 883 c +792 956 715 993 616 993 c +517 993 440 956 385 883 c +330 810 303 706 303 573 c +303 440 330 337 385 264 c +440 191 517 154 616 154 c +715 154 792 191 847 264 c +902 337 930 440 930 573 c + +1114 139 m +1114 -52 1072 -193 987 -286 c +902 -379 773 -426 598 -426 c +533 -426 472 -421 415 -411 c +358 -402 302 -387 248 -367 c +248 -188 l +302 -217 355 -239 408 -253 c +461 -267 514 -274 569 -274 c +690 -274 780 -242 840 -179 c +900 -116 930 -21 930 106 c +930 197 l +892 131 843 82 784 49 c +725 16 654 0 571 0 c +434 0 323 52 239 157 c +155 262 113 400 113 573 c +113 746 155 885 239 990 c +323 1095 434 1147 571 1147 c +654 1147 725 1131 784 1098 c +843 1065 892 1016 930 950 c +930 1120 l +1114 1120 l +1114 139 l + +678 1635 m +877 1635 l +551 1259 l +398 1259 l +678 1635 l + +ce} _d +/uni01F6{2279 0 201 -29 2093 1493 sc +201 1493 m +403 1493 l +403 881 l +1137 881 l +1137 1493 l +1339 1493 l +1339 449 l +1339 343 1360 263 1401 210 c +1442 158 1513 132 1615 131 c +1714 131 1785 157 1829 210 c +1870 260 1891 340 1891 449 c +1891 1120 l +2093 1120 l +2093 442 l +2093 293 2060 176 1993 91 c +1929 11 1803 -29 1615 -29 c +1432 -29 1306 11 1237 91 c +1170 170 1137 287 1137 442 c +1137 711 l +403 711 l +403 0 l +201 0 l +201 1493 l + +ce} _d +/uni01F7{1397 0 201 -426 1282 1520 sc +403 156 m +403 -426 l +201 -426 l +201 1493 l +403 1493 l +403 1308 l +440 1356 507 1409 604 1467 c +662 1502 766 1520 917 1520 c +1049 1520 1143 1480 1198 1400 c +1254 1319 1282 1223 1282 1114 c +1282 809 989 490 403 156 c + +403 351 m +852 638 1076 870 1076 1049 c +1076 1144 1056 1216 1015 1263 c +975 1310 912 1333 826 1333 c +668 1333 527 1247 403 1076 c +403 351 l + +ce} _d +/uni01F8{1532 0 201 0 1331 1899 sc +741 1899 m +937 1635 l +784 1635 l +554 1899 l +741 1899 l + +201 1493 m +473 1493 l +1135 244 l +1135 1493 l +1331 1493 l +1331 0 l +1059 0 l +397 1249 l +397 0 l +201 0 l +201 1493 l + +ce} _d +/uni01F9{1298 0 186 0 1124 1636 sc +1124 676 m +1124 0 l +940 0 l +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1027 c +1091 948 1124 831 1124 676 c + +647 1636 m +929 1262 l +776 1262 l +450 1636 l +647 1636 l + +ce} _d +/Aringacute{1401 0 16 0 1384 1907 sc +852 1626 m +852 1668 837 1704 807 1733 c +778 1763 742 1778 700 1778 c +657 1778 621 1763 592 1734 c +563 1705 549 1669 549 1626 c +549 1584 564 1548 593 1519 c +622 1490 658 1475 700 1475 c +742 1475 778 1490 807 1519 c +837 1548 852 1584 852 1626 c + +700 1294 m +428 551 l +973 551 l +700 1294 l + +549 1397 m +508 1424 478 1457 457 1495 c +436 1534 426 1577 426 1626 c +426 1703 452 1768 505 1821 c +558 1874 623 1901 700 1901 c +776 1901 841 1874 894 1820 c +948 1767 975 1702 975 1626 c +975 1579 964 1536 943 1497 c +922 1458 892 1424 852 1397 c +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +549 1397 l + +1171 1907 m +1356 1907 l +1128 1643 l +975 1643 l +1171 1907 l + +ce} _d +/aringacute{1255 0 123 -29 1244 1907 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +746 1524 m +746 1566 731 1602 702 1631 c +673 1660 637 1675 594 1675 c +551 1675 514 1660 485 1631 c +456 1602 442 1567 442 1524 c +442 1481 456 1444 485 1415 c +514 1386 551 1372 594 1372 c +637 1372 673 1387 702 1416 c +731 1445 746 1481 746 1524 c + +868 1524 m +868 1447 841 1382 788 1329 c +735 1276 671 1249 594 1249 c +517 1249 452 1276 399 1329 c +346 1382 320 1447 320 1524 c +320 1601 346 1665 399 1718 c +452 1771 517 1798 594 1798 c +671 1798 735 1771 788 1718 c +841 1665 868 1601 868 1524 c + +1059 1907 m +1244 1907 l +1016 1643 l +863 1643 l +1059 1907 l + +ce} _d +/AEacute{1995 0 8 0 1864 1900 sc +1171 1900 m +1356 1900 l +1128 1636 l +975 1636 l +1171 1900 l + +1845 1493 m +1845 1323 l +1104 1323 l +1104 881 l +1815 881 l +1815 711 l +1104 711 l +1104 170 l +1864 170 l +1864 0 l +901 0 l +901 383 l +373 383 l +213 0 l +8 0 l +633 1493 l +1845 1493 l + +772 1335 m +442 551 l +901 551 l +901 1335 l +772 1335 l + +ce} _d +/aeacute{2011 0 123 -29 1903 1635 sc +1718 660 m +1717 761 1689 841 1634 901 c +1579 961 1506 991 1415 991 c +1313 991 1231 962 1169 904 c +1108 846 1072 764 1063 659 c +1718 660 l + +995 963 m +1044 1023 1104 1069 1175 1100 c +1246 1131 1325 1147 1413 1147 c +1564 1147 1683 1098 1771 1001 c +1859 904 1903 773 1903 606 c +1903 516 l +1057 516 l +1065 389 1103 292 1171 225 c +1239 158 1334 125 1456 125 c +1525 125 1593 134 1660 151 c +1727 169 1793 196 1860 231 c +1860 57 l +1793 29 1725 8 1656 -7 c +1587 -22 1517 -29 1446 -29 c +1335 -29 1238 -9 1155 31 c +1072 72 1005 132 954 211 c +905 131 845 71 773 31 c +701 -9 617 -29 522 -29 c +396 -29 298 2 228 64 c +158 127 123 214 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +681 1147 763 1131 834 1099 c +905 1067 959 1022 995 963 c + +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1008 1635 m +1207 1635 l +881 1259 l +728 1259 l +1008 1635 l + +ce} _d +/Oslashacute{1612 0 102 -70 1509 1900 sc +821 1900 m +1006 1900 l +778 1636 l +625 1636 l +821 1900 l + +1206 1112 m +489 266 l +530 223 578 191 631 168 c +685 146 744 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 820 1277 888 1264 949 c +1251 1010 1232 1065 1206 1112 c + +1124 1225 m +1083 1268 1036 1300 982 1322 c +929 1345 870 1356 807 1356 c +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 670 334 602 347 539 c +360 476 380 422 406 377 c +1124 1225 l + +272 219 m +220 287 181 365 154 453 c +128 541 115 638 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c +894 1520 974 1507 1047 1481 c +1121 1456 1187 1418 1245 1368 c +1407 1559 l +1509 1470 l +1339 1272 l +1391 1203 1430 1125 1457 1036 c +1484 947 1497 850 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +722 -29 642 -17 568 8 c +495 33 428 71 367 121 c +205 -70 l +102 18 l +272 219 l + +ce} _d +/oslashacute{1253 0 72 -94 1180 1635 sc +905 801 m +418 209 l +445 181 476 160 510 147 c +545 134 584 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 612 943 657 936 696 c +929 735 919 770 905 801 c + +834 909 m +806 936 775 957 740 970 c +706 984 668 991 627 991 c +526 991 448 952 391 873 c +335 795 307 686 307 545 c +307 497 310 455 316 418 c +323 381 333 348 346 317 c +834 909 l + +221 166 m +185 217 158 276 140 341 c +122 407 113 480 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c +689 1147 746 1138 799 1121 c +852 1104 901 1079 946 1044 c +1085 1212 l +1180 1133 l +1034 954 l +1069 903 1096 844 1114 778 c +1132 712 1141 639 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +563 -29 504 -20 450 -3 c +397 14 349 40 307 74 c +168 -94 l +72 -16 l +221 166 l + +679 1635 m +878 1635 l +552 1259 l +399 1259 l +679 1635 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-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /DejaVuSans-2 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/uni0200 /uni0201 /uni0202 /uni0203 /uni0204 /uni0205 /uni0206 /uni0207 /uni0208 /uni0209 /uni020A /uni020B /uni020C /uni020D /uni020E /uni020F /uni0210 /uni0211 /uni0212 /uni0213 /uni0214 /uni0215 /uni0216 /uni0217 /Scommaaccent /scommaaccent /uni021A /uni021B /uni021C /uni021D /uni021E /uni021F /uni0220 /uni0221 /uni0222 /uni0223 /uni0224 /uni0225 /uni0226 /uni0227 /uni0228 /uni0229 /uni022A /uni022B /uni022C /uni022D /uni022E /uni022F /uni0230 /uni0231 /uni0232 /uni0233 /uni0234 /uni0235 /uni0236 /dotlessj /uni0238 /uni0239 /uni023A /uni023B /uni023C /uni023D /uni023E /uni023F /uni0240 /uni0241 /uni0242 /uni0243 /uni0244 /uni0245 /uni0246 /uni0247 /uni0248 /uni0249 /uni024A /uni024B /uni024C /uni024D /uni024E /uni024F /u1F600 /u1F601 /u1F602 /u1F603 /u1F604 /u1F605 /u1F606 /u1F607 /u1F608 /u1F609 /u1F60A /u1F60B /u1F60C /u1F60D /u1F60E /u1F60F] def +/CharStrings 97 dict dup begin +/.notdef 0 def +/uni0200{1401 0 16 0 1384 1904 sc +700 1294 m +426 551 l +975 551 l +700 1294 l + +586 1493 m +815 1493 l +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +586 1493 l + +492 1904 m +688 1640 l +535 1640 l +307 1904 l +492 1904 l + +827 1904 m +1023 1640 l +870 1640 l +642 1904 l +827 1904 l + +ce} _d +/uni0201{1255 0 123 -29 1069 1636 sc +423 1636 m +628 1260 l +493 1260 l +245 1636 l +423 1636 l + +757 1636 m +947 1260 l +810 1260 l +587 1636 l +757 1636 l + +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +ce} _d +/uni0202{1401 0 16 0 1384 1846 sc +700 1294 m +426 551 l +975 551 l +700 1294 l + +586 1493 m +815 1493 l +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +586 1493 l + +1013 1604 m +895 1604 l +886 1640 865 1667 832 1686 c +799 1705 755 1715 700 1715 c +645 1715 602 1706 569 1687 c +537 1669 516 1641 505 1604 c +387 1604 l +394 1683 424 1743 477 1784 c +530 1825 605 1846 700 1846 c +796 1846 870 1826 923 1785 c +976 1744 1006 1684 1013 1604 c + +ce} _d +/uni0203{1255 0 123 -29 1069 1608 sc +918 1321 m +800 1321 l +793 1371 773 1408 740 1433 c +708 1458 663 1471 605 1471 c +548 1471 503 1459 471 1434 c +439 1409 419 1372 410 1321 c +292 1321 l +299 1416 328 1488 381 1536 c +434 1584 508 1608 605 1608 c +702 1608 776 1584 829 1536 c +882 1488 911 1416 918 1321 c + +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +ce} _d +/uni0204{1294 0 201 0 1163 1904 sc +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +428 1904 m +624 1640 l +471 1640 l +243 1904 l +428 1904 l + +763 1904 m +959 1640 l +806 1640 l +578 1904 l +763 1904 l + +ce} _d +/uni0205{1260 0 113 -29 1151 1635 sc +457 1635 m +662 1259 l +527 1259 l +279 1635 l +457 1635 l + +791 1635 m +981 1259 l +844 1259 l +621 1635 l +791 1635 l + +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +ce} _d +/uni0206{1294 0 201 0 1163 1846 sc +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +991 1604 m +873 1604 l +864 1640 843 1667 810 1686 c +777 1705 733 1715 678 1715 c +623 1715 580 1706 547 1687 c +515 1669 494 1641 483 1604 c +365 1604 l +372 1683 402 1743 455 1784 c +508 1825 583 1846 678 1846 c +774 1846 848 1826 901 1785 c +954 1744 984 1684 991 1604 c + +ce} _d +/uni0207{1260 0 113 -29 1151 1608 sc +986 1321 m +868 1321 l +861 1371 841 1408 808 1433 c +776 1458 731 1471 673 1471 c +616 1471 571 1459 539 1434 c +507 1409 487 1372 478 1321 c +360 1321 l +367 1416 396 1488 449 1536 c +502 1584 576 1608 673 1608 c +770 1608 844 1584 897 1536 c +950 1488 979 1416 986 1321 c + +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +ce} _d +/uni0208{604 0 -89 0 627 1904 sc +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +96 1904 m +292 1640 l +139 1640 l +-89 1904 l +96 1904 l + +431 1904 m +627 1640 l +474 1640 l +246 1904 l +431 1904 l + +ce} _d +/uni0209{569 0 -61 0 641 1635 sc +117 1635 m +322 1259 l +187 1259 l +-61 1635 l +117 1635 l + +451 1635 m +641 1259 l +504 1259 l +281 1635 l +451 1635 l + +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +285 1147 m +285 1147 l + +ce} _d +/uni020A{604 0 5 0 631 1846 sc +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +631 1604 m +513 1604 l +504 1640 483 1667 450 1686 c +417 1705 373 1715 318 1715 c +263 1715 220 1706 187 1687 c +155 1669 134 1641 123 1604 c +5 1604 l +12 1683 42 1743 95 1784 c +148 1825 223 1846 318 1846 c +414 1846 488 1826 541 1785 c +594 1744 624 1684 631 1604 c + +ce} _d +/uni020B{569 0 -29 0 597 1608 sc +597 1321 m +479 1321 l +472 1371 452 1408 419 1433 c +387 1458 342 1471 284 1471 c +227 1471 182 1459 150 1434 c +118 1409 98 1372 89 1321 c +-29 1321 l +-22 1416 7 1488 60 1536 c +113 1584 187 1608 284 1608 c +381 1608 455 1584 508 1536 c +561 1488 590 1416 597 1321 c + +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +285 1147 m +285 1147 l + +ce} _d +/uni020C{1612 0 115 -29 1497 1904 sc +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +584 1904 m +780 1640 l +627 1640 l +399 1904 l +584 1904 l + +919 1904 m +1115 1640 l +962 1640 l +734 1904 l +919 1904 l + +ce} _d +/uni020D{1253 0 113 -29 1141 1636 sc +430 1636 m +635 1260 l +500 1260 l +252 1636 l +430 1636 l + +764 1636 m +954 1260 l +817 1260 l +594 1636 l +764 1636 l + +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +ce} _d +/uni020E{1612 0 115 -29 1497 1846 sc +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +1109 1604 m +991 1604 l +982 1640 961 1667 928 1686 c +895 1705 851 1715 796 1715 c +741 1715 698 1706 665 1687 c +633 1669 612 1641 601 1604 c +483 1604 l +490 1683 520 1743 573 1784 c +626 1825 701 1846 796 1846 c +892 1846 966 1826 1019 1785 c +1072 1744 1102 1684 1109 1604 c + +ce} _d +/uni020F{1253 0 113 -29 1141 1608 sc +969 1321 m +851 1321 l +844 1371 824 1408 791 1433 c +759 1458 714 1471 656 1471 c +599 1471 554 1459 522 1434 c +490 1409 470 1372 461 1321 c +343 1321 l +350 1416 379 1488 432 1536 c +485 1584 559 1608 656 1608 c +753 1608 827 1584 880 1536 c +933 1488 962 1416 969 1321 c + +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +ce} _d +/uni0210{1423 0 199 0 1364 1904 sc +909 700 m +952 685 994 654 1035 606 c +1076 558 1118 492 1159 408 c +1364 0 l +1147 0 l +956 383 l +907 483 859 549 812 582 c +766 615 703 631 623 631 c +403 631 l +403 0 l +201 0 l +201 1493 l +657 1493 l +828 1493 955 1457 1039 1386 c +1123 1315 1165 1207 1165 1063 c +1165 969 1143 891 1099 829 c +1056 767 992 724 909 700 c + +403 1327 m +403 797 l +657 797 l +754 797 828 819 877 864 c +927 909 952 976 952 1063 c +952 1150 927 1216 877 1260 c +828 1305 754 1327 657 1327 c +403 1327 l + +384 1904 m +580 1640 l +427 1640 l +199 1904 l +384 1904 l + +719 1904 m +915 1640 l +762 1640 l +534 1904 l +719 1904 l + +ce} _d +/uni0211{842 0 130 0 842 1635 sc +308 1635 m +513 1259 l +378 1259 l +130 1635 l +308 1635 l + +642 1635 m +832 1259 l +695 1259 l +472 1635 l +642 1635 l + +842 948 m +821 960 799 969 774 974 c +750 980 723 983 694 983 c +590 983 510 949 454 881 c +399 814 371 717 371 590 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +410 1014 460 1064 522 1097 c +584 1130 659 1147 748 1147 c +761 1147 775 1146 790 1144 c +805 1143 822 1140 841 1137 c +842 948 l + +ce} _d +/uni0212{1423 0 201 0 1364 1846 sc +909 700 m +952 685 994 654 1035 606 c +1076 558 1118 492 1159 408 c +1364 0 l +1147 0 l +956 383 l +907 483 859 549 812 582 c +766 615 703 631 623 631 c +403 631 l +403 0 l +201 0 l +201 1493 l +657 1493 l +828 1493 955 1457 1039 1386 c +1123 1315 1165 1207 1165 1063 c +1165 969 1143 891 1099 829 c +1056 767 992 724 909 700 c + +403 1327 m +403 797 l +657 797 l +754 797 828 819 877 864 c +927 909 952 976 952 1063 c +952 1150 927 1216 877 1260 c +828 1305 754 1327 657 1327 c +403 1327 l + +953 1604 m +835 1604 l +826 1640 805 1667 772 1686 c +739 1705 695 1715 640 1715 c +585 1715 542 1706 509 1687 c +477 1669 456 1641 445 1604 c +327 1604 l +334 1683 364 1743 417 1784 c +470 1825 545 1846 640 1846 c +736 1846 810 1826 863 1785 c +916 1744 946 1684 953 1604 c + +ce} _d +/uni0213{842 0 186 0 862 1608 sc +862 1321 m +744 1321 l +737 1371 717 1408 684 1433 c +652 1458 607 1471 549 1471 c +492 1471 447 1459 415 1434 c +383 1409 363 1372 354 1321 c +236 1321 l +243 1416 272 1488 325 1536 c +378 1584 452 1608 549 1608 c +646 1608 720 1584 773 1536 c +826 1488 855 1416 862 1321 c + +842 948 m +821 960 799 969 774 974 c +750 980 723 983 694 983 c +590 983 510 949 454 881 c +399 814 371 717 371 590 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +410 1014 460 1064 522 1097 c +584 1130 659 1147 748 1147 c +761 1147 775 1146 790 1144 c +805 1143 822 1140 841 1137 c +842 948 l + +ce} _d +/uni0214{1499 0 178 -29 1321 1904 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +540 1904 m +736 1640 l +583 1640 l +355 1904 l +540 1904 l + +875 1904 m +1071 1640 l +918 1640 l +690 1904 l +875 1904 l + +ce} _d +/uni0215{1298 0 174 -29 1112 1636 sc +483 1636 m +688 1260 l +553 1260 l +305 1636 l +483 1636 l + +817 1636 m +1007 1260 l +870 1260 l +647 1636 l +817 1636 l + +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +ce} _d +/uni0216{1499 0 178 -29 1321 1846 sc +178 1493 m +381 1493 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 1493 l +1321 1493 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 1493 l + +1061 1604 m +943 1604 l +934 1640 913 1667 880 1686 c +847 1705 803 1715 748 1715 c +693 1715 650 1706 617 1687 c +585 1669 564 1641 553 1604 c +435 1604 l +442 1683 472 1743 525 1784 c +578 1825 653 1846 748 1846 c +844 1846 918 1826 971 1785 c +1024 1744 1054 1684 1061 1604 c + +ce} _d +/uni0217{1298 0 174 -29 1112 1608 sc +988 1321 m +870 1321 l +863 1371 843 1408 810 1433 c +778 1458 733 1471 675 1471 c +618 1471 573 1459 541 1434 c +509 1409 489 1372 480 1321 c +362 1321 l +369 1416 398 1488 451 1536 c +504 1584 578 1608 675 1608 c +772 1608 846 1584 899 1536 c +952 1488 981 1416 988 1321 c + +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +ce} _d +/Scommaaccent{1300 0 135 -492 1186 1520 sc +562 -172 m +773 -172 l +609 -492 l +480 -492 l +562 -172 l + +1096 1444 m +1096 1247 l +1019 1284 947 1311 879 1329 c +811 1347 745 1356 682 1356 c +572 1356 487 1335 427 1292 c +368 1249 338 1189 338 1110 c +338 1044 358 994 397 960 c +437 927 512 900 623 879 c +745 854 l +896 825 1007 775 1078 702 c +1150 630 1186 533 1186 412 c +1186 267 1137 158 1040 83 c +943 8 801 -29 614 -29 c +543 -29 468 -21 388 -5 c +309 11 226 35 141 66 c +141 274 l +223 228 303 193 382 170 c +461 147 538 135 614 135 c +729 135 818 158 881 203 c +944 248 975 313 975 397 c +975 470 952 528 907 569 c +862 610 789 641 686 662 c +563 686 l +412 716 303 763 236 827 c +169 891 135 980 135 1094 c +135 1226 181 1330 274 1406 c +367 1482 496 1520 659 1520 c +729 1520 800 1514 873 1501 c +946 1488 1020 1469 1096 1444 c + +ce} _d +/scommaaccent{1067 0 111 -492 967 1147 sc +488 -172 m +699 -172 l +535 -492 l +406 -492 l +488 -172 l + +907 1087 m +907 913 l +855 940 801 960 745 973 c +689 986 631 993 571 993 c +480 993 411 979 365 951 c +320 923 297 881 297 825 c +297 782 313 749 346 724 c +379 700 444 677 543 655 c +606 641 l +737 613 829 573 884 522 c +939 471 967 400 967 309 c +967 205 926 123 843 62 c +761 1 648 -29 504 -29 c +444 -29 381 -23 316 -11 c +251 0 183 18 111 41 c +111 231 l +179 196 246 169 312 151 c +378 134 443 125 508 125 c +595 125 661 140 708 169 c +755 199 778 241 778 295 c +778 345 761 383 727 410 c +694 437 620 462 506 487 c +442 502 l +328 526 246 563 195 612 c +144 662 119 730 119 817 c +119 922 156 1004 231 1061 c +306 1118 412 1147 549 1147 c +617 1147 681 1142 741 1132 c +801 1122 856 1107 907 1087 c + +ce} _d +/uni021A{1251 0 -6 -492 1257 1493 sc +527 -172 m +738 -172 l +574 -492 l +445 -492 l +527 -172 l + +-6 1493 m +1257 1493 l +1257 1323 l +727 1323 l +727 0 l +524 0 l +524 1323 l +-6 1323 l +-6 1493 l + +ce} _d +/uni021B{803 0 55 -492 754 1438 sc +444 -172 m +655 -172 l +491 -492 l +362 -492 l +444 -172 l + +375 1438 m +375 1120 l +754 1120 l +754 977 l +375 977 l +375 369 l +375 278 387 219 412 193 c +437 167 488 154 565 154 c +754 154 l +754 0 l +565 0 l +423 0 325 26 271 79 c +217 132 190 229 190 369 c +190 977 l +55 977 l +55 1120 l +190 1120 l +190 1438 l +375 1438 l + +ce} _d +/uni021C{1284 0 156 -430 1139 1520 sc +831 674 m +1036 629 1139 509 1139 314 c +1139 239 1120 168 1083 99 c +1046 30 997 -31 935 -84 c +874 -137 800 -187 715 -232 c +630 -277 541 -316 448 -348 c +355 -380 258 -407 156 -430 c +156 -270 l +289 -233 407 -192 508 -145 c +610 -98 692 -50 753 1 c +815 52 861 104 892 156 c +923 209 938 261 938 314 c +938 381 917 437 875 481 c +834 525 776 547 701 547 c +638 547 568 530 491 496 c +328 424 l +328 595 l +576 701 l +616 718 653 738 687 759 c +721 781 755 808 790 841 c +825 874 852 914 872 960 c +893 1007 903 1057 903 1112 c +903 1149 897 1181 885 1210 c +874 1239 859 1261 840 1278 c +822 1295 800 1310 775 1321 c +750 1332 726 1340 702 1344 c +678 1348 653 1350 628 1350 c +505 1350 363 1289 201 1166 c +201 1356 l +360 1465 509 1520 646 1520 c +733 1520 811 1506 878 1477 c +946 1448 1001 1404 1042 1343 c +1083 1282 1104 1209 1104 1124 c +1104 1084 1100 1047 1092 1013 c +1085 979 1071 943 1052 905 c +1033 868 1005 830 968 791 c +931 752 886 713 831 674 c + +ce} _d +/uni021D{1068 0 71 -433 956 1147 sc +679 461 m +726 456 768 442 805 419 c +842 396 871 370 892 340 c +913 310 928 280 939 251 c +950 222 956 195 956 170 c +956 120 945 72 923 26 c +901 -20 872 -61 836 -97 c +800 -133 757 -167 706 -199 c +655 -232 604 -260 551 -283 c +499 -306 443 -328 383 -348 c +324 -369 269 -385 219 -398 c +170 -411 120 -423 71 -433 c +71 -303 l +179 -272 274 -241 355 -209 c +437 -177 504 -146 557 -115 c +610 -85 652 -54 685 -21 c +718 12 742 43 755 73 c +768 104 775 136 775 170 c +775 229 755 277 716 314 c +677 351 626 370 564 370 c +525 370 484 362 442 345 c +226 259 l +226 398 l +449 483 l +472 492 494 501 515 512 c +537 523 562 538 591 558 c +620 578 645 599 666 622 c +687 645 705 674 720 708 c +735 742 743 778 743 816 c +743 845 738 872 727 895 c +717 918 704 937 687 951 c +671 965 652 976 629 985 c +607 994 585 1001 563 1004 c +542 1007 519 1009 496 1009 c +450 1009 399 999 343 979 c +287 960 210 920 112 860 c +112 1014 l +289 1103 423 1147 512 1147 c +587 1147 655 1135 716 1111 c +777 1088 827 1052 866 1003 c +905 954 924 898 924 833 c +924 760 907 697 872 646 c +838 595 774 534 679 461 c + +ce} _d +/uni021E{1540 0 201 0 1339 1901 sc +678 1635 m +467 1901 l +606 1901 l +772 1723 l +938 1901 l +1077 1901 l +866 1635 l +678 1635 l + +201 1493 m +403 1493 l +403 881 l +1137 881 l +1137 1493 l +1339 1493 l +1339 0 l +1137 0 l +1137 711 l +403 711 l +403 0 l +201 0 l +201 1493 l + +ce} _d +/uni021F{1298 0 -16 0 1124 1901 sc +195 1635 m +-16 1901 l +123 1901 l +289 1723 l +455 1901 l +594 1901 l +383 1635 l +195 1635 l + +1124 676 m +1124 0 l +940 0 l +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1556 l +371 1556 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1027 c +1091 948 1124 831 1124 676 c + +ce} _d +/uni0220{1506 0 201 -426 1305 1521 sc +1104 895 m +1104 1038 1078 1145 1027 1216 c +976 1287 899 1323 797 1323 c +678 1323 582 1280 510 1195 c +439 1110 403 994 403 846 c +403 0 l +201 0 l +201 1493 l +403 1493 l +403 1252 l +457 1342 518 1409 586 1454 c +654 1499 740 1521 845 1520 c +996 1520 1111 1467 1188 1360 c +1266 1254 1305 1098 1305 893 c +1305 -426 l +1104 -426 l +1104 895 l + +ce} _d +/uni0221{1716 0 113 -144 1604 1556 sc +1206 130 m +1217 127 1235 125 1260 125 c +1367 125 1420 183 1420 300 c +1420 330 1403 345 1368 346 c +1333 346 1279 274 1206 130 c + +1114 314 m +1187 437 1269 498 1360 498 c +1523 498 1604 429 1604 292 c +1604 78 1490 -29 1262 -29 c +1213 -29 1171 -24 1136 -14 c +1113 -62 1094 -105 1078 -144 c +882 -144 l +901 -98 933 -26 978 72 c +946 112 930 144 930 168 c +891 101 843 52 784 20 c +725 -13 654 -29 571 -29 c +436 -29 325 25 240 133 c +155 241 113 383 113 559 c +113 735 155 877 240 985 c +325 1093 436 1147 571 1147 c +654 1147 725 1131 784 1098 c +843 1066 891 1017 930 950 c +930 1556 l +1114 1556 l +1114 314 l + +386 878 m +331 801 303 694 303 559 c +303 424 331 317 386 240 c +442 163 519 125 616 125 c +713 125 790 163 846 240 c +902 317 930 424 930 559 c +930 694 902 801 846 878 c +790 955 713 993 616 993 c +519 993 442 955 386 878 c + +ce} _d +/uni0222{1430 0 113 -29 1317 1520 sc +715 709 m +592 709 496 683 425 632 c +354 581 318 510 318 420 c +318 330 354 259 425 208 c +496 157 592 131 715 131 c +838 131 935 157 1006 208 c +1077 260 1113 331 1113 420 c +1113 510 1078 581 1007 632 c +936 683 839 709 715 709 c + +657 1260 m +570 1258 499 1236 442 1195 c +385 1154 357 1107 357 1054 c +357 1008 389 961 452 913 c +491 883 579 868 715 868 c +827 868 915 890 978 933 c +1042 976 1074 1043 1074 1134 c +1074 1239 1049 1306 998 1335 c +925 1386 846 1415 759 1420 c +759 1520 l +911 1520 1037 1485 1137 1416 c +1230 1351 1276 1257 1276 1133 c +1276 1048 1248 975 1191 916 c +1134 857 1055 816 954 795 c +1069 772 1158 728 1221 662 c +1285 596 1317 515 1317 420 c +1317 275 1265 164 1161 87 c +1058 10 909 -29 715 -29 c +521 -29 372 10 269 87 c +165 164 113 275 113 420 c +113 515 145 596 209 662 c +274 728 363 772 477 795 c +363 816 284 849 239 896 c +182 955 154 1014 154 1073 c +154 1160 197 1231 284 1286 c +361 1335 486 1360 657 1360 c +657 1260 l + +ce} _d +/uni0223{1250 0 113 -29 1137 1295 sc +625 709 m +529 709 453 683 398 632 c +343 581 316 510 316 420 c +316 330 343 259 398 208 c +453 157 529 131 625 131 c +721 131 797 157 852 208 c +907 260 935 331 935 420 c +935 510 907 581 852 632 c +797 683 722 709 625 709 c + +1024 1295 m +1063 1252 1082 1198 1082 1133 c +1082 1031 1065 959 1030 916 c +982 857 915 816 828 795 c +925 772 1001 728 1056 662 c +1110 596 1137 515 1137 420 c +1137 275 1093 164 1004 87 c +916 10 790 -29 625 -29 c +460 -29 334 10 246 87 c +157 164 113 275 113 420 c +113 515 140 596 195 662 c +250 728 326 772 423 795 c +327 818 259 859 220 916 c +185 966 168 1038 168 1133 c +168 1192 189 1246 231 1295 c +392 1295 l +363 1252 349 1191 349 1114 c +349 1037 373 976 422 933 c +470 890 538 868 625 868 c +712 868 779 890 828 933 c +877 976 902 1037 902 1114 c +902 1193 887 1254 858 1295 c +1024 1295 l + +ce} _d +/uni0224{1403 0 92 -426 1311 1493 sc +1311 -20 m +1311 -213 1258 -336 1153 -389 c +1105 -414 1043 -426 967 -426 c +713 -426 l +713 -270 l +946 -270 l +1016 -270 1064 -254 1089 -222 c +1114 -189 1127 -122 1127 -20 c +1127 0 l +92 0 l +92 154 l +1036 1323 l +115 1323 l +115 1493 l +1288 1493 l +1288 1339 l +344 170 l +1311 170 l +1311 -20 l + +ce} _d +/uni0225{1075 0 88 -426 987 1120 sc +987 -20 m +987 -213 934 -336 829 -389 c +781 -414 719 -426 643 -426 c +389 -426 l +389 -270 l +622 -270 l +692 -270 740 -254 765 -222 c +790 -189 803 -122 803 -20 c +803 0 l +88 0 l +88 168 l +780 973 l +113 973 l +113 1120 l +987 1120 l +987 952 l +295 147 l +987 147 l +987 -20 l + +ce} _d +/uni0226{1401 0 16 0 1384 1872 sc +598 1872 m +802 1872 l +802 1667 l +598 1667 l +598 1872 l + +700 1294 m +426 551 l +975 551 l +700 1294 l + +586 1493 m +815 1493 l +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +586 1493 l + +ce} _d +/uni0227{1255 0 123 -29 1069 1556 sc +492 1556 m +676 1556 l +676 1323 l +492 1323 l +492 1556 l + +586 1147 m +586 1147 l + +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +ce} _d +/uni0228{1294 0 201 -395 1163 1493 sc +201 1493 m +1145 1493 l +1145 1323 l +403 1323 l +403 881 l +1114 881 l +1114 711 l +403 711 l +403 170 l +1163 170 l +1163 0 l +201 0 l +201 1493 l + +758 0 m +795 -41 822 -79 840 -114 c +858 -149 867 -183 867 -215 c +867 -274 847 -319 807 -349 c +767 -380 708 -395 629 -395 c +598 -395 568 -393 539 -389 c +510 -385 482 -379 453 -371 c +453 -240 l +476 -251 499 -259 524 -264 c +549 -269 577 -272 608 -272 c +647 -272 677 -264 697 -248 c +717 -232 727 -209 727 -178 c +727 -158 720 -133 705 -104 c +691 -75 669 -41 639 0 c +758 0 l + +ce} _d +/uni0229{1260 0 113 -395 1151 1147 sc +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +719 0 m +756 -41 783 -79 801 -114 c +819 -149 828 -183 828 -215 c +828 -274 808 -319 768 -349 c +728 -380 669 -395 590 -395 c +559 -395 529 -393 500 -389 c +471 -385 443 -379 414 -371 c +414 -240 l +437 -251 460 -259 485 -264 c +510 -269 538 -272 569 -272 c +608 -272 638 -264 658 -248 c +678 -232 688 -209 688 -178 c +688 -158 681 -133 666 -104 c +652 -75 630 -41 600 0 c +719 0 l + +ce} _d +/uni022A{1612 0 115 -29 1497 2099 sc +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +500 2099 m +1098 2099 l +1098 1951 l +500 1951 l +500 2099 l + +892 1838 m +1095 1838 l +1095 1635 l +892 1635 l +892 1838 l + +501 1838 m +704 1838 l +704 1635 l +501 1635 l +501 1838 l + +ce} _d +/uni022B{1253 0 113 -29 1141 1841 sc +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +721 1552 m +924 1552 l +924 1350 l +721 1350 l +721 1552 l + +330 1552 m +533 1552 l +533 1350 l +330 1350 l +330 1552 l + +328 1841 m +926 1841 l +926 1693 l +328 1693 l +328 1841 l + +ce} _d +/uni022C{1612 0 115 -29 1497 2099 sc +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +805 1685 m +748 1718 l +731 1727 718 1734 707 1737 c +697 1741 688 1743 680 1743 c +656 1743 637 1735 624 1718 c +611 1701 604 1678 604 1648 c +604 1642 l +479 1642 l +479 1709 496 1763 530 1802 c +565 1841 611 1861 668 1861 c +692 1861 714 1858 734 1853 c +755 1848 781 1836 813 1818 c +870 1788 l +885 1779 899 1773 910 1769 c +921 1765 932 1763 942 1763 c +963 1763 981 1771 994 1788 c +1007 1805 1014 1828 1014 1855 c +1014 1861 l +1139 1861 l +1138 1794 1120 1741 1085 1701 c +1051 1662 1006 1642 950 1642 c +927 1642 906 1645 886 1650 c +867 1655 840 1667 805 1685 c + +507 2099 m +1105 2099 l +1105 1951 l +507 1951 l +507 2099 l + +ce} _d +/uni022D{1253 0 113 -29 1141 1769 sc +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +625 1355 m +568 1388 l +551 1397 538 1404 527 1407 c +517 1411 508 1413 500 1413 c +476 1413 457 1405 444 1388 c +431 1371 424 1348 424 1318 c +424 1312 l +299 1312 l +299 1379 316 1433 350 1472 c +385 1511 431 1531 488 1531 c +512 1531 534 1528 554 1523 c +575 1518 601 1506 633 1488 c +690 1458 l +705 1449 719 1443 730 1439 c +741 1435 752 1433 762 1433 c +783 1433 801 1441 814 1458 c +827 1475 834 1498 834 1525 c +834 1531 l +959 1531 l +958 1464 940 1411 905 1371 c +871 1332 826 1312 770 1312 c +747 1312 726 1315 706 1320 c +687 1325 660 1337 625 1355 c + +327 1769 m +925 1769 l +925 1621 l +327 1621 l +327 1769 l + +ce} _d +/uni022E{1612 0 115 -29 1497 1872 sc +705 1872 m +909 1872 l +909 1667 l +705 1667 l +705 1872 l + +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +ce} _d +/uni022F{1253 0 113 -29 1141 1556 sc +533 1556 m +717 1556 l +717 1323 l +533 1323 l +533 1556 l + +627 1147 m +627 1147 l + +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +ce} _d +/uni0230{1612 0 115 -29 1497 2099 sc +807 1356 m +660 1356 544 1301 457 1192 c +371 1083 328 934 328 745 c +328 557 371 408 457 299 c +544 190 660 135 807 135 c +954 135 1070 190 1155 299 c +1241 408 1284 557 1284 745 c +1284 934 1241 1083 1155 1192 c +1070 1301 954 1356 807 1356 c + +807 1520 m +1016 1520 1184 1450 1309 1309 c +1434 1169 1497 981 1497 745 c +1497 510 1434 322 1309 181 c +1184 41 1016 -29 807 -29 c +597 -29 429 41 303 181 c +178 321 115 509 115 745 c +115 981 178 1169 303 1309 c +429 1450 597 1520 807 1520 c + +704 1835 m +908 1835 l +908 1630 l +704 1630 l +704 1835 l + +508 2099 m +1106 2099 l +1106 1951 l +508 1951 l +508 2099 l + +ce} _d +/uni0231{1253 0 113 -29 1141 1841 sc +533 1556 m +717 1556 l +717 1323 l +533 1323 l +533 1556 l + +627 1147 m +627 1147 l + +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +328 1841 m +926 1841 l +926 1693 l +328 1693 l +328 1841 l + +ce} _d +/uni0232{1251 0 -4 0 1255 1841 sc +327 1841 m +925 1841 l +925 1693 l +327 1693 l +327 1841 l + +-4 1493 m +213 1493 l +627 879 l +1038 1493 l +1255 1493 l +727 711 l +727 0 l +524 0 l +524 711 l +-4 1493 l + +ce} _d +/uni0233{1212 0 61 -426 1151 1525 sc +307 1525 m +905 1525 l +905 1377 l +307 1377 l +307 1525 l + +659 -104 m +607 -237 556 -324 507 -365 c +458 -406 392 -426 309 -426 c +162 -426 l +162 -272 l +270 -272 l +321 -272 360 -260 388 -236 c +416 -212 447 -155 481 -66 c +514 18 l +61 1120 l +256 1120 l +606 244 l +956 1120 l +1151 1120 l +659 -104 l + +ce} _d +/uni0234{972 0 138 -144 860 1550 sc +462 130 m +473 127 491 125 516 125 c +623 125 676 183 676 300 c +676 330 659 345 624 346 c +589 346 535 274 462 130 c + +370 314 m +443 437 525 498 616 498 c +779 498 860 429 860 292 c +860 78 746 -29 518 -29 c +469 -29 427 -24 392 -14 c +369 -62 350 -105 334 -144 c +138 -144 l +157 -98 189 -26 234 72 c +201 112 185 162 186 222 c +186 1550 l +370 1550 l +370 314 l + +ce} _d +/uni0235{1726 0 186 -144 1614 1147 sc +1216 130 m +1227 127 1245 125 1270 125 c +1377 125 1430 183 1430 300 c +1430 330 1413 345 1378 346 c +1343 346 1289 274 1216 130 c + +1124 314 m +1197 437 1279 498 1370 498 c +1533 498 1614 429 1614 292 c +1614 78 1500 -29 1272 -29 c +1223 -29 1181 -24 1146 -14 c +1123 -62 1104 -105 1088 -144 c +892 -144 l +911 -98 943 -26 988 72 c +955 112 939 162 940 222 c +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1028 c +1091 948 1124 831 1124 676 c +1124 314 l + +ce} _d +/uni0236{977 0 55 -144 865 1438 sc +467 130 m +478 127 496 125 521 125 c +628 125 681 183 681 300 c +681 330 664 345 629 346 c +594 346 540 274 467 130 c + +375 314 m +448 437 530 498 621 498 c +784 498 865 429 865 292 c +865 78 751 -29 523 -29 c +474 -29 432 -24 396 -14 c +374 -62 355 -105 339 -144 c +143 -144 l +162 -98 194 -26 239 72 c +206 112 190 162 190 222 c +190 977 l +55 977 l +55 1120 l +190 1120 l +190 1438 l +375 1438 l +375 1120 l +754 1120 l +754 977 l +375 977 l +375 314 l + +ce} _d +/dotlessj{569 0 -37 -426 377 1120 sc +193 1120 m +377 1120 l +377 -20 l +377 -163 350 -266 295 -330 c +241 -394 154 -426 33 -426 c +-37 -426 l +-37 -270 l +12 -270 l +82 -270 130 -254 155 -221 c +180 -189 193 -122 193 -20 c +193 1120 l + +ce} _d +/uni0238{2044 0 113 -29 1932 1556 sc +386 878 m +331 801 303 694 303 559 c +303 424 331 317 386 240 c +442 163 519 125 616 125 c +713 125 790 163 846 240 c +902 317 930 424 930 559 c +930 694 902 800 846 877 c +790 954 713 993 616 993 c +519 993 442 955 386 878 c + +571 1147 m +734 1147 854 1081 930 950 c +930 1556 l +1115 1556 l +1115 950 l +1191 1081 1310 1147 1473 1147 c +1609 1147 1719 1093 1804 985 c +1889 877 1932 735 1932 559 c +1932 383 1889 241 1804 133 c +1719 25 1609 -29 1473 -29 c +1310 -29 1191 37 1115 168 c +1115 0 l +930 0 l +930 168 l +854 37 734 -29 571 -29 c +436 -29 325 25 240 133 c +155 241 113 383 113 559 c +113 735 155 877 240 985 c +325 1093 436 1147 571 1147 c + +1658 240 m +1713 317 1741 424 1741 559 c +1741 694 1713 801 1658 878 c +1602 955 1525 993 1428 993 c +1331 993 1254 955 1198 878 c +1143 801 1115 694 1115 559 c +1115 424 1143 317 1198 240 c +1254 163 1331 125 1428 125 c +1525 125 1602 163 1658 240 c + +ce} _d +/uni0239{2044 0 113 -426 1932 1147 sc +1658 240 m +1713 317 1741 424 1741 559 c +1741 694 1713 801 1658 878 c +1602 955 1525 993 1428 993 c +1331 993 1254 955 1198 878 c +1143 801 1115 694 1115 559 c +1115 424 1143 317 1198 240 c +1254 163 1331 125 1428 125 c +1525 125 1602 163 1658 240 c + +1473 -29 m +1310 -29 1191 37 1115 168 c +1115 -426 l +930 -426 l +930 168 l +854 37 734 -29 571 -29 c +436 -29 325 25 240 133 c +155 241 113 383 113 559 c +113 735 155 877 240 985 c +325 1093 436 1147 571 1147 c +734 1147 854 1081 930 950 c +930 1120 l +1115 1120 l +1115 950 l +1191 1081 1310 1147 1473 1147 c +1609 1147 1719 1093 1804 985 c +1889 877 1932 735 1932 559 c +1932 383 1889 241 1804 133 c +1719 25 1609 -29 1473 -29 c + +386 878 m +331 801 303 694 303 559 c +303 424 331 317 386 240 c +442 163 519 125 616 125 c +713 125 790 163 846 240 c +902 317 930 424 930 559 c +930 694 902 800 846 877 c +790 954 713 993 616 993 c +519 993 442 955 386 878 c + +ce} _d +/uni023A{1401 0 -3 -70 1404 1559 sc +586 1493 m +815 1493 l +949 1142 l +1302 1559 l +1404 1470 l +1004 997 l +1384 0 l +1174 0 l +1038 383 l +484 383 l +279 142 l +229 0 l +159 0 l +100 -70 l +18 0 l +16 0 l +17 1 l +-3 18 l +44 74 l +586 1493 l + +700 1294 m +426 551 l +448 551 l +815 984 l +700 1294 l + +626 551 m +975 551 l +869 838 l +626 551 l + +ce} _d +/uni023B{1430 0 12 -70 1418 1559 sc +114 -70 m +12 18 l +232 279 l +154 404 115 559 115 745 c +115 985 180 1174 310 1312 c +440 1451 618 1520 844 1520 c +933 1520 1017 1508 1096 1484 c +1137 1472 1176 1457 1215 1439 c +1316 1559 l +1418 1470 l +1319 1352 l +1319 1165 l +1288 1194 1257 1219 1224 1241 c +444 319 l +450 310 457 302 464 294 c +555 189 685 137 856 137 c +943 137 1025 153 1102 184 c +1179 215 1251 263 1319 326 c +1319 115 l +1248 67 1173 31 1094 7 c +1015 -17 932 -29 844 -29 c +623 -29 447 37 318 170 c +114 -70 l + +375 447 m +1103 1307 l +1102 1307 l +1025 1338 943 1354 856 1354 c +685 1354 555 1302 464 1198 c +373 1093 328 942 328 745 c +328 630 344 530 375 447 c + +ce} _d +/uni023C{1126 0 9 -94 1117 1212 sc +105 -94 m +9 -16 l +198 214 l +141 308 113 423 113 559 c +113 742 163 885 264 990 c +364 1095 501 1147 676 1147 c +733 1147 788 1141 842 1130 c +873 1123 903 1115 933 1104 c +1022 1212 l +1117 1133 l +999 990 l +999 905 l +982 914 966 923 950 930 c +393 256 l +398 251 402 245 406 240 c +472 165 565 127 684 127 c +737 127 790 134 842 148 c +895 163 947 184 999 213 c +999 43 l +948 19 895 1 840 -11 c +785 -23 726 -29 664 -29 c +504 -29 375 19 277 115 c +105 -94 l + +332 376 m +826 974 l +779 985 731 991 684 991 c +565 991 472 953 406 878 c +340 802 307 696 307 559 c +307 490 315 429 332 376 c + +ce} _d +/uni023D{1141 0 10 0 1130 1493 sc +201 1493 m +403 1493 l +403 844 l +594 844 l +594 700 l +403 700 l +403 170 l +1130 170 l +1130 0 l +201 0 l +201 700 l +10 700 l +10 844 l +201 844 l +201 1493 l + +ce} _d +/uni023E{1251 0 -78 -70 1329 1559 sc +1257 1385 m +1257 1323 l +1205 1323 l +727 759 l +727 0 l +524 0 l +524 519 l +25 -70 l +-78 18 l +524 729 l +524 1323 l +-6 1323 l +-6 1493 l +1171 1493 l +1227 1559 l +1329 1470 l +1257 1385 l + +727 969 m +1027 1323 l +727 1323 l +727 969 l + +ce} _d +/uni023F{1067 0 111 -496 1049 1147 sc +778 295 m +778 345 761 383 728 410 c +694 437 620 462 506 487 c +442 502 l +328 526 246 563 195 612 c +144 662 119 730 119 817 c +119 922 156 1004 231 1061 c +306 1118 412 1147 549 1147 c +617 1147 681 1142 741 1132 c +801 1122 856 1107 907 1087 c +907 913 l +855 940 801 960 745 973 c +689 986 631 993 571 993 c +480 993 411 979 366 951 c +320 923 297 881 297 825 c +297 782 313 749 346 724 c +379 700 444 677 543 655 c +606 641 l +738 612 831 572 884 522 c +939 471 967 400 967 309 c +967 205 926 123 844 62 c +786 19 713 -8 625 -21 c +784 -180 l +931 -306 l +959 -330 998 -342 1049 -342 c +1049 -496 l +1010 -496 l +954 -496 888 -476 812 -435 c +765 -410 711 -367 652 -306 c +415 -63 l +395 -43 373 -28 349 -17 c +338 -15 327 -13 316 -12 c +251 0 183 18 111 41 c +111 231 l +179 196 246 169 312 152 c +378 134 443 125 508 125 c +595 125 661 140 708 170 c +755 199 778 241 778 295 c + +ce} _d +/uni0240{1075 0 88 -496 1075 1120 sc +113 1120 m +987 1120 l +987 952 l +297 149 l +358 138 405 117 438 84 c +702 -180 l +849 -306 l +877 -330 916 -342 967 -342 c +1075 -342 l +1075 -496 l +928 -496 l +872 -496 806 -476 730 -435 c +683 -410 629 -367 570 -306 c +333 -63 l +292 -21 242 0 182 0 c +88 0 l +88 156 l +88 168 l +780 973 l +113 973 l +113 1120 l + +ce} _d +/uni0241{1235 0 80 0 1165 1493 sc +657 602 m +618 602 l +618 0 l +416 0 l +416 768 l +657 768 l +751 768 824 792 875 840 c +926 889 952 958 952 1048 c +952 1139 926 1208 875 1255 c +824 1303 751 1327 657 1327 c +403 1327 l +357 1327 305 1320 246 1306 c +188 1292 133 1270 80 1241 c +80 1423 l +181 1470 289 1493 403 1493 c +657 1493 l +820 1493 945 1456 1033 1383 c +1121 1310 1165 1198 1165 1048 c +1165 905 1121 794 1032 717 c +944 640 819 602 657 602 c + +ce} _d +/uni0242{981 0 80 0 911 1147 sc +303 422 m +403 422 l +497 422 570 446 621 494 c +672 543 698 612 698 702 c +698 796 673 865 622 908 c +565 956 492 980 403 980 c +354 980 301 973 244 959 c +187 945 132 924 80 895 c +80 1077 l +181 1124 289 1147 403 1147 c +570 1147 696 1110 779 1037 c +867 960 911 848 911 702 c +911 560 876 451 805 374 c +734 298 634 260 505 260 c +505 0 l +303 0 l +303 422 l + +ce} _d +/uni0243{1405 0 10 0 1260 1493 sc +403 713 m +403 512 l +750 512 l +750 368 l +403 368 l +403 166 l +727 166 l +836 166 916 188 968 233 c +1021 278 1047 347 1047 440 c +1047 533 1021 602 968 646 c +916 691 836 713 727 713 c +403 713 l + +403 1327 m +403 877 l +702 877 l +801 877 874 895 922 932 c +971 969 995 1026 995 1102 c +995 1177 971 1234 922 1271 c +874 1308 801 1327 702 1327 c +403 1327 l + +201 1493 m +717 1493 l +871 1493 990 1461 1073 1397 c +1156 1333 1198 1242 1198 1124 c +1198 1033 1177 960 1134 906 c +1091 852 1029 818 946 805 c +1045 784 1122 739 1177 671 c +1232 604 1260 519 1260 418 c +1260 285 1215 182 1124 109 c +1033 36 904 0 737 0 c +201 0 l +201 368 l +10 368 l +10 512 l +201 512 l +201 1493 l + +ce} _d +/uni0244{1499 0 12 -29 1486 1493 sc +178 1493 m +381 1493 l +381 875 l +1118 875 l +1118 1493 l +1321 1493 l +1321 875 l +1486 875 l +1486 711 l +1321 711 l +1321 561 l +1321 366 1273 219 1176 120 c +1080 21 938 -29 750 -29 c +561 -29 419 21 322 120 c +226 219 178 366 178 561 c +178 711 l +12 711 l +12 875 l +178 875 l +178 1493 l + +1118 711 m +381 711 l +381 586 l +381 426 410 311 468 240 c +526 170 620 135 750 135 c +879 135 973 170 1031 240 c +1089 311 1118 426 1118 586 c +1118 711 l + +ce} _d +/uni0245{1401 0 16 0 1384 1493 sc +229 0 m +16 0 l +586 1493 l +815 1493 l +1384 0 l +1174 0 l +700 1294 l +229 0 l + +ce} _d +/uni0246{1294 0 201 -190 1163 1683 sc +952 1683 m +1122 1683 l +1057 1493 l +1145 1493 l +1145 1323 l +999 1323 l +848 881 l +1114 881 l +1114 711 l +790 711 l +605 170 l +1163 170 l +1163 0 l +547 0 l +482 -190 l +312 -190 l +377 0 l +201 0 l +201 1493 l +887 1493 l +952 1683 l + +435 170 m +620 711 l +403 711 l +403 170 l +435 170 l + +678 881 m +829 1323 l +403 1323 l +403 881 l +678 881 l + +ce} _d +/uni0247{1260 0 113 -190 1151 1310 sc +967 660 m +966 761 937 841 882 901 c +873 912 863 921 852 930 c +741 660 l +967 660 l + +1151 606 m +1151 516 l +682 516 l +534 155 l +583 136 640 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +612 -29 538 -18 472 4 c +392 -190 l +222 -190 l +331 75 l +309 90 289 108 270 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +699 1147 734 1144 767 1138 c +838 1310 l +1008 1310 l +916 1086 l +954 1063 989 1035 1020 1002 c +1107 905 1151 773 1151 606 c + +571 659 m +706 989 l +693 990 679 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +571 659 l + +401 246 m +512 516 l +305 516 l +312 401 344 311 401 246 c + +ce} _d +/uni0248{604 0 -106 -410 594 1493 sc +594 631 m +403 631 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 631 l +10 631 l +10 797 l +201 797 l +201 1493 l +403 1493 l +403 797 l +594 797 l +594 631 l + +ce} _d +/uni0249{569 0 -37 -426 540 1556 sc +193 1120 m +377 1120 l +377 616 l +540 616 l +540 452 l +377 452 l +377 -20 l +377 -163 350 -266 295 -330 c +241 -394 154 -426 33 -426 c +-37 -426 l +-37 -270 l +12 -270 l +82 -270 130 -254 155 -221 c +180 -189 193 -122 193 -20 c +193 452 l +12 452 l +12 616 l +193 616 l +193 1120 l + +193 1556 m +377 1556 l +377 1323 l +193 1323 l +193 1556 l + +ce} _d +/uni024A{1600 0 115 -410 1712 1521 sc +1203 1261 m +1203 1493 l +1399 1493 l +1399 104 l +1399 -25 1417 -115 1454 -165 c +1491 -215 1554 -240 1643 -240 c +1712 -240 l +1712 -410 l +1635 -410 l +1484 -410 1374 -369 1305 -288 c +1237 -207 1203 -76 1203 104 c +1203 231 l +1152 143 1087 78 1008 35 c +929 -8 835 -29 725 -29 c +545 -29 398 42 285 184 c +172 327 115 514 115 746 c +115 978 172 1165 285 1307 c +398 1450 545 1521 725 1521 c +835 1521 929 1500 1008 1457 c +1087 1414 1152 1349 1203 1261 c + +325 745 m +325 555 364 406 442 297 c +520 189 627 135 763 135 c +900 135 1007 189 1085 297 c +1164 406 1203 555 1203 745 c +1203 935 1164 1084 1085 1192 c +1007 1301 900 1355 763 1355 c +627 1355 520 1301 442 1192 c +364 1084 325 935 325 745 c + +ce} _d +/uni024B{1300 0 113 -426 1344 1147 sc +1344 -426 m +1274 -426 l +1153 -426 1066 -394 1011 -330 c +957 -266 930 -163 930 -20 c +930 168 l +891 101 842 52 783 19 c +724 -13 654 -29 571 -29 c +436 -29 325 25 240 133 c +155 241 113 383 113 559 c +113 735 155 877 240 985 c +325 1093 436 1147 571 1147 c +654 1147 724 1131 783 1098 c +842 1066 891 1017 930 950 c +930 1120 l +1114 1120 l +1114 -20 l +1114 -122 1127 -189 1152 -221 c +1177 -254 1225 -270 1295 -270 c +1344 -270 l +1344 -426 l + +303 559 m +303 424 331 317 386 240 c +442 163 519 125 616 125 c +713 125 790 163 846 240 c +902 317 930 424 930 559 c +930 694 902 800 846 877 c +790 954 713 993 616 993 c +519 993 442 954 386 877 c +331 800 303 694 303 559 c + +ce} _d +/uni024C{1423 0 10 0 1364 1493 sc +909 700 m +952 685 994 654 1035 606 c +1076 558 1118 492 1159 408 c +1364 0 l +1147 0 l +956 383 l +907 483 859 549 812 582 c +766 615 703 631 623 631 c +403 631 l +403 0 l +201 0 l +201 631 l +10 631 l +10 797 l +201 797 l +201 1493 l +657 1493 l +828 1493 955 1457 1039 1386 c +1123 1315 1165 1207 1165 1063 c +1165 969 1143 891 1099 829 c +1056 767 992 724 909 700 c + +403 1327 m +403 797 l +657 797 l +754 797 828 819 877 864 c +927 909 952 976 952 1063 c +952 1150 927 1216 877 1260 c +828 1305 754 1327 657 1327 c +403 1327 l + +ce} _d +/uni024D{842 0 14 0 842 1147 sc +542 616 m +542 452 l +371 452 l +371 0 l +186 0 l +186 452 l +14 452 l +14 616 l +186 616 l +186 1120 l +371 1120 l +371 946 l +410 1014 460 1064 522 1097 c +584 1130 659 1147 748 1147 c +761 1147 775 1146 790 1144 c +805 1143 822 1140 841 1137 c +842 948 l +821 960 799 969 774 974 c +750 980 723 983 694 983 c +590 983 510 949 454 880 c +399 811 371 723 371 616 c +542 616 l + +ce} _d +/uni024E{1251 0 -10 0 1260 1493 sc +-4 1493 m +213 1493 l +364 1269 l +888 1269 l +1038 1493 l +1255 1493 l +1104 1269 l +1260 1269 l +1260 1105 l +993 1105 l +727 711 l +727 0 l +524 0 l +524 711 l +258 1105 l +-10 1105 l +-10 1269 l +147 1269 l +-4 1493 l + +778 1105 m +475 1105 l +627 879 l +778 1105 l + +ce} _d +/uni024F{1212 0 11 -426 1205 1120 sc +659 -104 m +607 -237 556 -324 507 -365 c +458 -406 392 -426 309 -426 c +162 -426 l +162 -272 l +270 -272 l +321 -272 360 -260 388 -236 c +416 -212 447 -155 481 -66 c +514 18 l +309 516 l +11 516 l +11 659 l +251 659 l +61 1120 l +256 1120 l +440 659 l +772 659 l +956 1120 l +1151 1120 l +966 659 l +1205 659 l +1205 516 l +908 516 l +659 -104 l + +715 516 m +497 516 l +606 244 l +715 516 l + +ce} _d +/u1F600{2135 0 170 -150 1965 1646 sc +642 1023 m +642 1062 655 1095 682 1122 c +709 1149 743 1163 782 1163 c +821 1163 854 1149 881 1122 c +908 1095 922 1062 922 1023 c +922 984 908 951 881 923 c +854 896 821 882 782 882 c +743 882 709 896 682 923 c +655 951 642 984 642 1023 c + +1220 1023 m +1220 1062 1234 1095 1261 1122 c +1288 1149 1321 1163 1360 1163 c +1399 1163 1432 1149 1459 1122 c +1487 1095 1501 1062 1501 1023 c +1501 984 1487 951 1459 923 c +1432 896 1399 882 1360 882 c +1321 882 1287 896 1260 923 c +1233 951 1220 984 1220 1023 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +446 736 m +1689 736 l +1689 564 1628 418 1507 297 c +1386 176 1240 116 1068 116 c +896 116 749 176 628 297 c +507 418 446 564 446 736 c + +1136 255 m +1195 262 1249 280 1300 308 c +1300 601 l +1136 601 l +1136 255 l + +1000 255 m +1000 601 l +836 601 l +836 308 l +887 280 941 262 1000 255 c + +1436 419 m +1484 474 1517 534 1536 601 c +1436 601 l +1436 419 l + +700 417 m +700 601 l +599 601 l +618 533 651 472 700 417 c + +ce} _d +/u1F601{2135 0 170 -150 1965 1646 sc +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +1126 908 m +1126 1001 1149 1080 1196 1145 c +1243 1211 1299 1244 1364 1244 c +1429 1244 1485 1211 1532 1145 c +1579 1080 1602 1001 1602 908 c +1467 908 l +1467 963 1457 1011 1436 1050 c +1416 1090 1392 1110 1364 1110 c +1336 1110 1312 1090 1291 1050 c +1271 1011 1261 963 1261 908 c +1126 908 l + +534 908 m +534 1001 557 1080 604 1145 c +651 1211 707 1244 772 1244 c +837 1244 893 1211 940 1145 c +987 1080 1010 1001 1010 908 c +875 908 l +875 963 865 1011 844 1050 c +824 1090 800 1110 772 1110 c +744 1110 720 1090 699 1050 c +679 1011 669 963 669 908 c +534 908 l + +446 736 m +1689 736 l +1689 564 1628 418 1507 297 c +1386 176 1240 116 1068 116 c +896 116 749 176 628 297 c +507 418 446 564 446 736 c + +1136 255 m +1195 262 1249 280 1300 308 c +1300 601 l +1136 601 l +1136 255 l + +1000 255 m +1000 601 l +836 601 l +836 308 l +887 280 941 262 1000 255 c + +1436 419 m +1484 474 1517 534 1536 601 c +1436 601 l +1436 419 l + +700 417 m +700 601 l +599 601 l +618 533 651 472 700 417 c + +ce} _d +/u1F602{2393 0 95 -150 2297 1646 sc +828 417 m +828 601 l +727 601 l +746 533 779 472 828 417 c + +1564 419 m +1612 474 1645 534 1664 601 c +1564 601 l +1564 419 l + +1128 255 m +1128 601 l +964 601 l +964 308 l +1015 280 1069 262 1128 255 c + +1264 255 m +1323 262 1377 280 1428 308 c +1428 601 l +1264 601 l +1264 255 l + +574 736 m +1817 736 l +1817 564 1756 418 1635 297 c +1514 176 1368 116 1196 116 c +1024 116 877 176 756 297 c +635 418 574 564 574 736 c + +662 908 m +662 1001 685 1080 732 1145 c +779 1211 835 1244 900 1244 c +965 1244 1021 1211 1068 1145 c +1115 1080 1138 1001 1138 908 c +1003 908 l +1003 963 993 1011 972 1050 c +952 1090 928 1110 900 1110 c +872 1110 848 1090 827 1050 c +807 1011 797 963 797 908 c +662 908 l + +1254 908 m +1254 1001 1277 1080 1324 1145 c +1371 1211 1427 1244 1492 1244 c +1557 1244 1613 1211 1660 1145 c +1707 1080 1730 1001 1730 908 c +1595 908 l +1595 963 1585 1011 1564 1050 c +1544 1090 1520 1110 1492 1110 c +1464 1110 1440 1090 1419 1050 c +1399 1011 1389 963 1389 908 c +1254 908 l + +298 746 m +298 995 386 1207 561 1382 c +736 1558 948 1646 1196 1646 c +1445 1646 1656 1558 1831 1382 c +2006 1207 2093 995 2093 746 c +2093 727 2092 708 2091 690 c +2184 659 l +2223 646 2251 631 2267 615 c +2287 594 2297 572 2297 547 c +2297 522 2288 500 2270 482 c +2252 464 2230 455 2205 455 c +2180 455 2157 465 2136 486 c +2119 503 2105 530 2093 568 c +2082 600 l +2054 414 1970 251 1831 112 c +1656 -63 1445 -150 1196 -150 c +948 -150 736 -63 561 112 c +422 251 338 413 309 598 c +299 568 l +287 530 273 503 256 486 c +235 465 212 455 187 455 c +162 455 140 464 122 482 c +104 500 95 522 95 547 c +95 572 105 594 125 615 c +140 632 168 646 208 659 c +300 689 l +299 708 298 727 298 746 c + +433 746 m +433 535 507 356 656 207 c +805 59 985 -15 1196 -15 c +1407 -15 1587 59 1735 207 c +1884 356 1958 535 1958 746 c +1958 759 1958 772 1957 785 c +1939 768 1918 759 1893 759 c +1868 759 1845 769 1824 790 c +1807 807 1793 834 1781 872 c +1736 1008 l +1872 963 l +1899 954 1921 944 1937 934 c +1906 1067 1839 1184 1736 1287 c +1588 1436 1408 1511 1196 1511 c +985 1511 805 1436 656 1287 c +553 1184 486 1066 455 934 c +471 945 493 954 520 963 c +656 1008 l +611 872 l +599 834 585 807 568 790 c +547 769 524 759 499 759 c +474 759 452 768 434 786 c +433 773 433 759 433 746 c + +ce} _d +/u1F603{2135 0 170 -150 1965 1646 sc +642 1023 m +642 1062 655 1095 682 1122 c +709 1149 743 1163 782 1163 c +821 1163 854 1149 881 1122 c +908 1095 922 1062 922 1023 c +922 984 908 951 881 923 c +854 896 821 882 782 882 c +743 882 709 896 682 923 c +655 951 642 984 642 1023 c + +1220 1023 m +1220 1062 1234 1095 1261 1122 c +1288 1149 1321 1163 1360 1163 c +1399 1163 1432 1149 1459 1122 c +1487 1095 1501 1062 1501 1023 c +1501 984 1487 951 1459 923 c +1432 896 1399 882 1360 882 c +1321 882 1287 896 1260 923 c +1233 951 1220 984 1220 1023 c + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +446 736 m +1689 736 l +1689 564 1628 418 1507 297 c +1386 176 1240 116 1068 116 c +896 116 749 176 628 297 c +507 418 446 564 446 736 c + +1536 601 m +599 601 l +621 523 663 453 724 392 c +819 297 933 250 1068 250 c +1203 251 1317 298 1412 393 c +1473 454 1515 524 1536 601 c + +ce} _d +/u1F604{2135 0 170 -150 1965 1646 sc +534 908 m +534 1001 557 1080 604 1145 c +651 1211 707 1244 772 1244 c +837 1244 893 1211 940 1145 c +987 1080 1010 1001 1010 908 c +875 908 l +875 963 865 1011 844 1050 c +824 1090 800 1110 772 1110 c +744 1110 720 1090 699 1050 c +679 1011 669 963 669 908 c +534 908 l + +1126 908 m +1126 1001 1149 1080 1196 1145 c +1243 1211 1299 1244 1364 1244 c +1429 1244 1485 1211 1532 1145 c +1579 1080 1602 1001 1602 908 c +1467 908 l +1467 963 1457 1011 1436 1050 c +1416 1090 1392 1110 1364 1110 c +1336 1110 1312 1090 1291 1050 c +1271 1011 1261 963 1261 908 c +1126 908 l + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +446 736 m +1689 736 l +1689 564 1628 418 1507 297 c +1386 176 1240 116 1068 116 c +896 116 749 176 628 297 c +507 418 446 564 446 736 c + +1536 601 m +599 601 l +621 523 663 453 724 392 c +819 297 933 250 1068 251 c +1203 251 1317 298 1412 393 c +1473 454 1515 524 1536 601 c + +ce} _d +/u1F605{2135 0 170 -150 1965 1646 sc +1704 1068 m +1769 940 l +1788 903 1797 873 1796 850 c +1795 821 1786 798 1769 781 c +1751 763 1729 754 1704 754 c +1679 754 1657 763 1639 781 c +1621 799 1612 823 1612 852 c +1612 875 1621 905 1639 940 c +1704 1068 l + +534 908 m +534 1001 557 1080 604 1145 c +651 1211 707 1244 772 1244 c +837 1244 893 1211 940 1145 c +987 1080 1010 1001 1010 908 c +875 908 l +875 963 865 1011 844 1050 c +824 1090 800 1110 772 1110 c +744 1110 720 1090 699 1050 c +679 1011 669 963 669 908 c +534 908 l + +1126 908 m +1126 1001 1149 1080 1196 1145 c +1243 1211 1299 1244 1364 1244 c +1429 1244 1485 1211 1532 1145 c +1579 1080 1602 1001 1602 908 c +1467 908 l +1467 963 1457 1011 1436 1050 c +1416 1090 1392 1110 1364 1110 c +1336 1110 1312 1090 1291 1050 c +1271 1011 1261 963 1261 908 c +1126 908 l + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +446 736 m +1689 736 l +1689 564 1628 418 1507 297 c +1386 176 1240 116 1068 116 c +896 116 749 176 628 297 c +507 418 446 564 446 736 c + +1536 601 m +599 601 l +621 523 663 453 724 392 c +819 297 933 250 1068 251 c +1203 251 1317 298 1412 393 c +1473 454 1515 524 1536 601 c + +ce} _d +/u1F606{2135 0 170 -150 1965 1646 sc +1148 1063 m +1443 1269 l +1520 1159 l +1322 1020 l +1520 882 l +1443 772 l +1148 978 l +1148 1063 l + +988 1063 m +988 978 l +693 772 l +616 882 l +814 1020 l +616 1159 l +693 1269 l +988 1063 l + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +446 736 m +1689 736 l +1689 564 1628 418 1507 297 c +1386 176 1240 116 1068 116 c +896 116 749 176 628 297 c +507 418 446 564 446 736 c + +1536 601 m +599 601 l +621 523 663 453 724 392 c +819 297 933 250 1068 250 c +1203 251 1317 298 1412 393 c +1473 454 1515 524 1536 601 c + +ce} _d +/u1F607{2135 0 143 -150 1992 1891 sc +541 465 m +656 536 l +675 507 697 479 724 454 c +819 360 934 313 1068 312 c +1203 312 1317 359 1412 454 c +1438 480 1461 508 1480 537 c +1595 465 l +1570 427 1541 391 1508 358 c +1387 237 1240 177 1068 177 c +896 177 749 237 628 358 c +595 392 566 428 541 465 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1608 1287 c +1594 1301 l +1441 1263 1266 1244 1068 1244 c +871 1244 695 1263 542 1301 c +528 1287 l +379 1138 304 957 305 746 c + +1220 1021 m +1220 1060 1234 1093 1261 1120 c +1288 1147 1321 1161 1360 1161 c +1399 1161 1432 1147 1459 1120 c +1487 1093 1501 1060 1501 1021 c +1501 982 1487 949 1459 921 c +1432 894 1399 880 1360 880 c +1321 880 1287 894 1260 921 c +1233 949 1220 982 1220 1021 c + +642 1021 m +642 1060 655 1093 682 1120 c +709 1147 743 1161 782 1161 c +821 1161 854 1147 881 1120 c +908 1093 922 1060 922 1021 c +922 982 908 948 881 921 c +854 894 821 880 782 880 c +743 880 709 894 682 921 c +655 949 642 982 642 1021 c + +143 1567 m +143 1656 233 1733 414 1796 c +595 1859 813 1891 1068 1891 c +1324 1891 1542 1859 1722 1796 c +1902 1733 1992 1656 1992 1567 c +1992 1480 1908 1406 1739 1345 c +1890 1177 1965 977 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c +170 977 246 1177 397 1345 c +228 1406 143 1480 143 1567 c + +1642 1439 m +1767 1475 1830 1518 1830 1567 c +1830 1621 1756 1667 1607 1705 c +1459 1743 1279 1762 1068 1762 c +857 1762 677 1743 528 1705 c +379 1667 305 1621 305 1567 c +305 1518 368 1475 494 1439 c +657 1577 848 1646 1068 1646 c +1289 1646 1480 1577 1642 1439 c + +1466 1401 m +1349 1474 1216 1511 1068 1511 c +921 1511 788 1474 671 1401 c +788 1382 921 1373 1068 1373 c +1216 1373 1349 1382 1466 1401 c + +ce} _d +/u1F608{2135 0 170 -150 1965 1840 sc +722 1383 m +1025 1171 l +948 1060 l +645 1273 l +722 1383 l + +1220 949 m +1220 988 1234 1021 1261 1048 c +1288 1075 1321 1089 1360 1089 c +1399 1089 1432 1075 1459 1048 c +1487 1021 1501 988 1501 949 c +1501 910 1487 877 1459 849 c +1432 822 1399 808 1360 808 c +1321 808 1287 822 1260 849 c +1233 877 1220 910 1220 949 c + +642 949 m +642 988 655 1021 682 1048 c +709 1075 743 1089 782 1089 c +821 1089 854 1075 881 1048 c +908 1021 922 988 922 949 c +922 910 908 876 881 849 c +854 822 821 808 782 808 c +743 808 709 822 682 849 c +655 877 642 910 642 949 c + +1414 1383 m +1491 1273 l +1188 1060 l +1111 1171 l +1414 1383 l + +541 465 m +656 536 l +675 507 697 479 724 454 c +819 359 933 312 1068 312 c +1203 312 1317 359 1412 454 c +1438 480 1461 508 1480 537 c +1595 465 l +1570 427 1541 391 1508 358 c +1387 237 1240 177 1068 177 c +896 177 749 237 628 358 c +595 392 566 428 541 465 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +787 1604 m +875 1632 969 1646 1068 1646 c +1167 1646 1261 1632 1349 1604 c +1792 1840 l +1792 1280 l +1907 1126 1965 948 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c +170 948 228 1126 344 1280 c +344 1840 l +787 1604 l + +ce} _d +/u1F609{2135 0 170 -150 1965 1646 sc +541 465 m +656 536 l +675 507 697 479 724 454 c +819 359 933 312 1068 312 c +1203 312 1317 359 1412 454 c +1438 480 1461 508 1480 537 c +1595 465 l +1570 427 1541 391 1508 358 c +1387 237 1240 177 1068 177 c +896 177 749 237 628 358 c +595 392 566 428 541 465 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +642 1021 m +642 1060 655 1093 682 1120 c +709 1147 743 1161 782 1161 c +821 1161 854 1147 881 1120 c +908 1093 922 1060 922 1021 c +922 982 908 948 881 921 c +854 894 821 880 782 880 c +743 880 709 894 682 921 c +655 949 642 982 642 1021 c + +1148 1063 m +1443 1269 l +1520 1159 l +1322 1020 l +1520 882 l +1443 772 l +1148 978 l +1148 1063 l + +ce} _d +/u1F60A{2135 0 170 -150 1965 1646 sc +541 465 m +656 536 l +675 507 697 479 724 454 c +819 359 933 312 1068 312 c +1203 312 1317 359 1412 454 c +1438 480 1461 508 1480 537 c +1595 465 l +1570 427 1541 391 1508 358 c +1387 237 1240 177 1068 177 c +896 177 749 237 628 358 c +595 392 566 428 541 465 c + +534 908 m +534 1001 557 1080 604 1145 c +651 1211 707 1244 772 1244 c +837 1244 893 1211 940 1145 c +987 1080 1010 1001 1010 908 c +875 908 l +875 963 865 1011 844 1050 c +824 1090 800 1110 772 1110 c +744 1110 720 1090 699 1050 c +679 1011 669 963 669 908 c +534 908 l + +1126 908 m +1126 1001 1149 1080 1196 1145 c +1243 1211 1299 1244 1364 1244 c +1429 1244 1485 1211 1532 1145 c +1579 1080 1602 1001 1602 908 c +1467 908 l +1467 963 1457 1011 1436 1050 c +1416 1090 1392 1110 1364 1110 c +1336 1110 1312 1090 1291 1050 c +1271 1011 1261 963 1261 908 c +1126 908 l + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +ce} _d +/u1F60B{2135 0 170 -150 1965 1646 sc +1126 908 m +1126 1001 1149 1080 1196 1145 c +1243 1211 1299 1244 1364 1244 c +1429 1244 1485 1211 1532 1145 c +1579 1080 1602 1001 1602 908 c +1467 908 l +1467 963 1457 1011 1436 1050 c +1416 1090 1392 1110 1364 1110 c +1336 1110 1312 1090 1291 1050 c +1271 1011 1261 963 1261 908 c +1126 908 l + +534 908 m +534 1001 557 1080 604 1145 c +651 1211 707 1244 772 1244 c +837 1244 893 1211 940 1145 c +987 1080 1010 1001 1010 908 c +875 908 l +875 963 865 1011 844 1050 c +824 1090 800 1110 772 1110 c +744 1110 720 1090 699 1050 c +679 1011 669 963 669 908 c +534 908 l + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1159 -15 1243 -1 1322 26 c +1255 58 1199 110 1156 182 c +1127 179 1098 177 1068 177 c +896 177 749 237 628 358 c +507 479 446 625 446 797 c +581 797 l +581 662 628 548 723 453 c +818 359 933 312 1068 312 c +1203 312 1317 359 1412 454 c +1507 549 1554 663 1554 797 c +1689 797 l +1689 655 1648 531 1566 424 c +1603 357 1621 291 1621 225 c +1621 221 l +1760 366 1830 541 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +1466 320 m +1413 275 1356 241 1295 217 c +1316 190 1339 169 1364 153 c +1388 138 1409 130 1427 130 c +1438 130 1447 133 1456 138 c +1478 151 1489 176 1490 214 c +1490 217 1490 221 1489 225 c +1488 256 1480 287 1466 320 c + +ce} _d +/u1F60C{2135 0 170 -150 1965 1646 sc +541 465 m +656 536 l +675 507 697 479 724 454 c +819 359 933 312 1068 312 c +1203 312 1317 359 1412 454 c +1438 480 1461 508 1480 537 c +1595 465 l +1570 427 1541 391 1508 358 c +1387 237 1240 177 1068 177 c +896 177 749 237 628 358 c +595 392 566 428 541 465 c + +1602 1160 m +1602 1067 1579 988 1532 922 c +1485 857 1429 824 1364 824 c +1299 824 1243 857 1196 922 c +1149 988 1126 1067 1126 1160 c +1261 1160 l +1261 1105 1271 1057 1291 1017 c +1312 978 1336 958 1364 958 c +1392 958 1416 978 1436 1017 c +1457 1057 1467 1105 1467 1160 c +1602 1160 l + +1010 1160 m +1010 1067 987 988 940 922 c +893 857 837 824 772 824 c +707 824 651 857 604 922 c +557 988 534 1067 534 1160 c +669 1160 l +669 1105 679 1057 699 1017 c +720 978 744 958 772 958 c +800 958 824 978 844 1017 c +865 1057 875 1105 875 1160 c +1010 1160 l + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +ce} _d +/u1F60D{2135 0 170 -150 1965 1646 sc +1446 1216 m +1463 1216 1480 1211 1497 1202 c +1537 1177 1557 1144 1557 1102 c +1556 1059 1539 1016 1506 975 c +1338 768 l +1336 768 l +1177 958 l +1136 1003 1115 1051 1115 1102 c +1114 1116 1117 1131 1124 1148 c +1149 1193 1183 1216 1225 1216 c +1252 1215 1277 1204 1298 1183 c +1317 1162 1329 1135 1336 1102 c +1337 1102 l +1337 1111 1341 1126 1350 1145 c +1373 1192 1405 1216 1446 1216 c + +690 1216 m +731 1216 763 1192 786 1145 c +795 1126 799 1111 799 1102 c +800 1102 l +807 1135 819 1162 838 1183 c +859 1204 884 1215 911 1216 c +953 1216 987 1193 1012 1148 c +1019 1131 1022 1116 1021 1102 c +1021 1051 1000 1003 959 958 c +800 768 l +798 768 l +630 975 l +597 1016 580 1059 579 1102 c +579 1144 599 1177 639 1202 c +656 1211 673 1216 690 1216 c + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 c + +541 465 m +656 536 l +675 507 697 479 724 454 c +819 359 933 312 1068 312 c +1203 312 1317 359 1412 454 c +1438 480 1461 508 1480 537 c +1595 465 l +1570 427 1541 391 1508 358 c +1387 237 1240 177 1068 177 c +896 177 749 237 628 358 c +595 392 566 428 541 465 c + +ce} _d +/u1F60E{2135 0 170 -150 1965 1646 sc +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 876 1802 994 1746 1101 c +1636 1101 l +1636 1022 l +1636 955 1608 898 1553 851 c +1498 804 1431 780 1352 780 c +1273 780 1206 804 1151 851 c +1096 898 1068 955 1068 1022 c +1068 955 1040 898 985 851 c +930 804 863 780 784 780 c +705 780 638 804 583 851 c +528 898 500 955 500 1022 c +500 1101 l +390 1101 l +333 994 305 876 305 746 c + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +541 465 m +656 536 l +675 507 697 479 724 454 c +819 360 934 313 1068 312 c +1203 312 1317 359 1412 454 c +1438 480 1461 508 1480 537 c +1595 465 l +1570 427 1541 391 1508 358 c +1387 237 1240 177 1068 177 c +896 177 749 237 628 358 c +595 392 566 428 541 465 c + +482 1236 m +1654 1236 l +1639 1253 1624 1270 1608 1287 c +1460 1436 1280 1511 1068 1511 c +857 1511 677 1436 528 1287 c +512 1270 497 1253 482 1236 c + +ce} _d +/u1F60F{2135 0 170 -150 1965 1646 sc +1176 908 m +1176 1043 l +1602 1043 l +1602 908 l +1176 908 l + +534 908 m +534 1043 l +960 1043 l +960 908 l +534 908 l + +1068 312 m +1203 312 1317 359 1412 454 c +1438 480 1461 508 1480 537 c +1595 465 l +1570 427 1541 391 1508 358 c +1387 237 1240 177 1068 177 c +1068 312 l + +170 746 m +170 995 258 1207 433 1382 c +608 1558 820 1646 1068 1646 c +1317 1646 1528 1558 1703 1382 c +1878 1207 1965 995 1965 746 c +1965 498 1878 287 1703 112 c +1528 -63 1317 -150 1068 -150 c +820 -150 608 -63 433 112 c +258 287 170 498 170 746 c + +305 746 m +305 535 379 356 528 207 c +677 59 857 -15 1068 -15 c +1279 -15 1459 59 1607 207 c +1756 356 1830 535 1830 746 c +1830 957 1756 1138 1607 1287 c +1459 1436 1279 1511 1068 1511 c +857 1511 677 1436 528 1287 c +379 1138 305 957 305 746 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 +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-0 16.000 selectfont +gsave + +195.836 362.531 translate +0 rotate +0 0 m /T glyphshow +11.5625 0 m /h glyphshow +20.4531 0 m /e glyphshow +27.5625 0 m /r glyphshow +33.8281 0 m /e glyphshow +40.9375 0 m /space glyphshow +46.2656 0 m /a glyphshow +54.2656 0 m /r glyphshow +60.5312 0 m /e glyphshow +67.6406 0 m /space glyphshow +72.9688 0 m /b glyphshow +81.8594 0 m /a glyphshow +89.8594 0 m /s glyphshow +96.1719 0 m /i glyphshow +100.609 0 m /c glyphshow +107.719 0 m /space glyphshow +113.047 0 m /c glyphshow +120.156 0 m /h glyphshow +129.047 0 m /a glyphshow +137.047 0 m /r glyphshow +143.312 0 m /a glyphshow +151.312 0 m /c glyphshow +158.422 0 m /t glyphshow +164.641 0 m /e glyphshow +171.75 0 m /r glyphshow +178.016 0 m /s glyphshow +grestore +/Cmr10-0 16.000 selectfont +gsave + +34.5859 347.781 translate +0 rotate +0 0 m /A glyphshow +12 0 m /B glyphshow +23.3281 0 m /C glyphshow +34.8906 0 m /D glyphshow +47.1094 0 m /E glyphshow +58 0 m /F glyphshow +68.4375 0 m /G glyphshow +80.9844 0 m /H glyphshow +92.9844 0 m /I glyphshow +98.7656 0 m /J glyphshow +106.984 0 m /K glyphshow +119.422 0 m /L glyphshow +129.422 0 m /M glyphshow +144.078 0 m /N glyphshow +156.078 0 m /O glyphshow +168.516 0 m /P glyphshow +179.406 0 m /Q glyphshow +191.844 0 m /R glyphshow +203.625 0 m /S glyphshow +212.516 0 m /T glyphshow +224.078 0 m /U glyphshow +236.078 0 m /V glyphshow +248.078 0 m /W glyphshow +264.516 0 m /X glyphshow +276.516 0 m /Y glyphshow +288.516 0 m /Z glyphshow +298.297 0 m /space glyphshow +303.625 0 m /a glyphshow +311.625 0 m /b glyphshow +320.516 0 m /c glyphshow +327.625 0 m /d glyphshow +336.516 0 m /e glyphshow +343.625 0 m /f glyphshow +348.516 0 m /g glyphshow +356.516 0 m /h glyphshow +365.406 0 m /i glyphshow +369.844 0 m /j glyphshow +374.734 0 m /k glyphshow +383.172 0 m /l glyphshow +387.609 0 m /m glyphshow +400.938 0 m /n glyphshow +409.828 0 m /o glyphshow +417.828 0 m /p glyphshow +426.719 0 m /q glyphshow +435.156 0 m /r glyphshow +441.422 0 m /s glyphshow +447.734 0 m /t glyphshow +453.953 0 m /u glyphshow +462.844 0 m /v glyphshow +471.281 0 m /w glyphshow +482.844 0 m /x glyphshow +491.281 0 m /y glyphshow +499.719 0 m /z glyphshow +grestore +/Cmr10-0 16.000 selectfont +gsave + +122.281 332.484 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.7656 0 m /quotedblright glyphshow +97.7656 0 m /numbersign glyphshow +111.094 0 m /dollar glyphshow +119.094 0 m /percent glyphshow +132.422 0 m /ampersand glyphshow +144.859 0 m /quoteright glyphshow +149.297 0 m /parenleft glyphshow +155.516 0 m /parenright glyphshow +161.734 0 m /asterisk glyphshow +169.734 0 m /plus glyphshow +182.172 0 m /comma glyphshow +186.609 0 m /hyphen glyphshow +191.938 0 m /period glyphshow +196.375 0 m /slash glyphshow +204.375 0 m /colon glyphshow +208.812 0 m /semicolon glyphshow +213.25 0 m /exclamdown glyphshow +217.688 0 m /equal glyphshow +230.125 0 m /questiondown glyphshow +237.688 0 m /question glyphshow +245.25 0 m /at glyphshow +257.688 0 m /bracketleft glyphshow +262.125 0 m /quotedblleft glyphshow +270.125 0 m /bracketright glyphshow +274.562 0 m /circumflex glyphshow +282.562 0 m /dotaccent glyphshow +287 0 m /quoteleft glyphshow +291.438 0 m /emdash glyphshow +299.438 0 m /endash glyphshow +315.438 0 m /hungarumlaut glyphshow +323.438 0 m /tilde glyphshow +grestore +/Cmr10-0 16.000 selectfont +gsave + +203.922 317.203 translate +0 rotate +0 0 m /a glyphshow +8 0 m /n glyphshow +16.8906 0 m /d glyphshow +25.7812 0 m /space glyphshow +31.1094 0 m /a glyphshow +39.1094 0 m /c glyphshow +46.2188 0 m /c glyphshow +53.3281 0 m /e glyphshow +60.4375 0 m /n glyphshow +69.3281 0 m /t glyphshow +75.5469 0 m /e glyphshow +82.6562 0 m /d glyphshow +91.5469 0 m /space glyphshow +96.875 0 m /c glyphshow +103.984 0 m /h glyphshow +112.875 0 m /a glyphshow +120.875 0 m /r glyphshow +127.141 0 m /a glyphshow +135.141 0 m /c glyphshow +142.25 0 m /t glyphshow +148.469 0 m /e glyphshow +155.578 0 m /r glyphshow +161.844 0 m /s glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +144.602 299.047 translate +0 rotate +0 0 m /Aring glyphshow +10.9531 0 m /AE glyphshow +26.5469 0 m /Ccedilla glyphshow +37.7188 0 m /Egrave glyphshow +47.8281 0 m /Eacute glyphshow +57.9375 0 m /Ecircumflex glyphshow +68.0469 0 m /Edieresis glyphshow +78.1562 0 m /Igrave glyphshow +82.875 0 m /Iacute glyphshow +87.5938 0 m /Icircumflex glyphshow +92.3125 0 m /Idieresis glyphshow +97.0312 0 m /Eth glyphshow +109.438 0 m /Ntilde glyphshow +121.406 0 m /Ograve glyphshow +134 0 m /Oacute glyphshow +146.594 0 m /Ocircumflex glyphshow +159.188 0 m /Otilde glyphshow +171.781 0 m /Odieresis glyphshow +184.375 0 m /multiply glyphshow +197.781 0 m /Oslash glyphshow +210.375 0 m /Ugrave glyphshow +222.094 0 m /Uacute glyphshow +233.812 0 m /Ucircumflex glyphshow +245.531 0 m /Udieresis glyphshow +257.25 0 m /Yacute glyphshow +267.031 0 m /Thorn glyphshow +276.719 0 m /germandbls glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +136.82 281.703 translate +0 rotate +0 0 m /agrave glyphshow +9.8125 0 m /aacute glyphshow +19.625 0 m /acircumflex glyphshow +29.4375 0 m /atilde glyphshow +39.25 0 m /adieresis glyphshow +49.0625 0 m /aring glyphshow +58.875 0 m /ae glyphshow +74.5938 0 m /ccedilla glyphshow +83.3906 0 m /egrave glyphshow +93.2344 0 m /eacute glyphshow +103.078 0 m /ecircumflex glyphshow +112.922 0 m /edieresis glyphshow +122.766 0 m /igrave glyphshow +127.219 0 m /iacute glyphshow +131.672 0 m /icircumflex glyphshow +136.125 0 m /idieresis glyphshow +140.578 0 m /eth glyphshow +150.375 0 m /ntilde glyphshow +160.516 0 m /ograve glyphshow +170.312 0 m /oacute glyphshow +180.109 0 m /ocircumflex glyphshow +189.906 0 m /otilde glyphshow +199.703 0 m /odieresis glyphshow +209.5 0 m /divide glyphshow +222.906 0 m /oslash glyphshow +232.703 0 m /ugrave glyphshow +242.844 0 m /uacute glyphshow +252.984 0 m /ucircumflex glyphshow +263.125 0 m /udieresis glyphshow +273.266 0 m /yacute glyphshow +282.734 0 m /thorn glyphshow +292.891 0 m /ydieresis glyphshow +grestore +/DejaVuSans-1 16.000 selectfont +gsave + +121.945 263.234 translate +0 rotate +0 0 m /Amacron glyphshow +10.9531 0 m /amacron glyphshow +20.7656 0 m /Abreve glyphshow +31.7188 0 m /abreve glyphshow +41.5312 0 m /Aogonek glyphshow +52.4844 0 m /aogonek glyphshow +62.2969 0 m /Cacute glyphshow +73.4688 0 m /cacute glyphshow +82.2656 0 m /Ccircumflex glyphshow +93.4375 0 m /ccircumflex glyphshow +102.234 0 m /Cdotaccent glyphshow +113.406 0 m /cdotaccent glyphshow +122.203 0 m /Ccaron glyphshow +133.375 0 m /ccaron glyphshow +142.172 0 m /Dcaron glyphshow +154.5 0 m /dcaron glyphshow +164.656 0 m /Dcroat glyphshow +177.062 0 m /dcroat glyphshow +187.219 0 m /Emacron glyphshow +197.328 0 m /emacron glyphshow +207.172 0 m /Ebreve glyphshow +217.281 0 m /ebreve glyphshow +227.125 0 m /Edotaccent glyphshow +237.234 0 m /edotaccent glyphshow +247.078 0 m /Eogonek glyphshow +257.188 0 m /eogonek glyphshow +267.031 0 m /Ecaron glyphshow +277.141 0 m /ecaron glyphshow +286.984 0 m /Gcircumflex glyphshow +299.391 0 m /gcircumflex glyphshow +309.547 0 m /Gbreve glyphshow +321.953 0 m /gbreve glyphshow +grestore +/DejaVuSans-1 16.000 selectfont +gsave + +164.969 245.047 translate +0 rotate +0 0 m /Gdotaccent glyphshow +12.4062 0 m /gdotaccent glyphshow +22.5625 0 m /Gcommaaccent glyphshow +34.9688 0 m /gcommaaccent glyphshow +45.125 0 m /Hcircumflex glyphshow +57.1562 0 m /hcircumflex glyphshow +67.2969 0 m /Hbar glyphshow +81.9531 0 m /hbar glyphshow +93.0781 0 m /Itilde glyphshow +97.7969 0 m /itilde glyphshow +102.25 0 m /Imacron glyphshow +106.969 0 m /imacron glyphshow +111.422 0 m /Ibreve glyphshow +116.141 0 m /ibreve glyphshow +120.594 0 m /Iogonek glyphshow +125.312 0 m /iogonek glyphshow +129.766 0 m /Idotaccent glyphshow +134.484 0 m /dotlessi glyphshow +138.938 0 m /IJ glyphshow +148.375 0 m /ij glyphshow +157.266 0 m /Jcircumflex glyphshow +161.984 0 m /jcircumflex glyphshow +166.438 0 m /Kcommaaccent glyphshow +176.938 0 m /kcommaaccent glyphshow +186.203 0 m /kgreenlandic glyphshow +195.469 0 m /Lacute glyphshow +204.391 0 m /lacute glyphshow +208.844 0 m /Lcommaaccent glyphshow +217.766 0 m /lcommaaccent glyphshow +222.219 0 m /Lcaron glyphshow +231.141 0 m /lcaron glyphshow +237.141 0 m /Ldot glyphshow +grestore +/DejaVuSans-1 16.000 selectfont +gsave + +123.125 226.188 translate +0 rotate +0 0 m /ldot glyphshow +5.46875 0 m /Lslash glyphshow +14.4688 0 m /lslash glyphshow +19.0156 0 m /Nacute glyphshow +30.9844 0 m /nacute glyphshow +41.125 0 m /Ncommaaccent glyphshow +53.0938 0 m /ncommaaccent glyphshow +63.2344 0 m /Ncaron glyphshow +75.2031 0 m /ncaron glyphshow +85.3438 0 m /napostrophe glyphshow +98.3594 0 m /Eng glyphshow +110.328 0 m /eng glyphshow +120.469 0 m /Omacron glyphshow +133.062 0 m /omacron glyphshow +142.859 0 m /Obreve glyphshow +155.453 0 m /obreve glyphshow +165.25 0 m /Ohungarumlaut glyphshow +177.844 0 m /ohungarumlaut glyphshow +187.641 0 m /OE glyphshow +204.766 0 m /oe glyphshow +221.141 0 m /Racute glyphshow +232.266 0 m /racute glyphshow +238.844 0 m /Rcommaaccent glyphshow +249.969 0 m /rcommaaccent glyphshow +256.547 0 m /Rcaron glyphshow +267.672 0 m /rcaron glyphshow +274.25 0 m /Sacute glyphshow +284.406 0 m /sacute glyphshow +292.75 0 m /Scircumflex glyphshow +302.906 0 m /scircumflex glyphshow +311.25 0 m /Scedilla glyphshow +321.406 0 m /scedilla glyphshow +grestore +/DejaVuSans-1 16.000 selectfont +gsave + +128.219 207.516 translate +0 rotate +0 0 m /Scaron glyphshow +10.1562 0 m /scaron glyphshow +18.5 0 m /Tcommaaccent glyphshow +28.2812 0 m /tcommaaccent glyphshow +34.5625 0 m /Tcaron glyphshow +44.3438 0 m /tcaron glyphshow +50.625 0 m /Tbar glyphshow +60.4062 0 m /tbar glyphshow +66.6875 0 m /Utilde glyphshow +78.4062 0 m /utilde glyphshow +88.5469 0 m /Umacron glyphshow +100.266 0 m /umacron glyphshow +110.406 0 m /Ubreve glyphshow +122.125 0 m /ubreve glyphshow +132.266 0 m /Uring glyphshow +143.984 0 m /uring glyphshow +154.125 0 m /Uhungarumlaut glyphshow +165.844 0 m /uhungarumlaut glyphshow +175.984 0 m /Uogonek glyphshow +187.703 0 m /uogonek glyphshow +197.844 0 m /Wcircumflex glyphshow +213.672 0 m /wcircumflex glyphshow +226.766 0 m /Ycircumflex glyphshow +236.547 0 m /ycircumflex glyphshow +246.016 0 m /Ydieresis glyphshow +255.797 0 m /Zacute glyphshow +266.766 0 m /zacute glyphshow +275.172 0 m /Zdotaccent glyphshow +286.141 0 m /zdotaccent glyphshow +294.547 0 m /Zcaron glyphshow +305.516 0 m /zcaron glyphshow +313.922 0 m /longs glyphshow +grestore +/DejaVuSans-1 16.000 selectfont +gsave + +120.906 189.406 translate +0 rotate +0 0 m /uni0180 glyphshow +10.1562 0 m /uni0181 glyphshow +21.9219 0 m /uni0182 glyphshow +32.9062 0 m /uni0183 glyphshow +43.0625 0 m /uni0184 glyphshow +54.0469 0 m /uni0185 glyphshow +64.2031 0 m /uni0186 glyphshow +75.4531 0 m /uni0187 glyphshow +86.625 0 m /uni0188 glyphshow +95.4219 0 m /uni0189 glyphshow +107.828 0 m /uni018A glyphshow +120.938 0 m /uni018B glyphshow +131.922 0 m /uni018C glyphshow +142.078 0 m /uni018D glyphshow +151.875 0 m /uni018E glyphshow +161.984 0 m /uni018F glyphshow +174.578 0 m /uni0190 glyphshow +184.406 0 m /uni0191 glyphshow +193.609 0 m /florin glyphshow +199.25 0 m /uni0193 glyphshow +211.656 0 m /uni0194 glyphshow +222.641 0 m /uni0195 glyphshow +238.391 0 m /uni0196 glyphshow +244.047 0 m /uni0197 glyphshow +248.766 0 m /uni0198 glyphshow +260.703 0 m /uni0199 glyphshow +269.969 0 m /uni019A glyphshow +274.422 0 m /uni019B glyphshow +283.891 0 m /uni019C glyphshow +299.484 0 m /uni019D glyphshow +311.453 0 m /uni019E glyphshow +321.594 0 m /uni019F glyphshow +grestore +/DejaVuSans-1 16.000 selectfont +gsave + +124.211 173.891 translate +0 rotate +0 0 m /Ohorn glyphshow +14.6094 0 m /ohorn glyphshow +24.4062 0 m /uni01A2 glyphshow +39.5938 0 m /uni01A3 glyphshow +51.75 0 m /uni01A4 glyphshow +62.1875 0 m /uni01A5 glyphshow +72.3438 0 m /uni01A6 glyphshow +83.4688 0 m /uni01A7 glyphshow +93.625 0 m /uni01A8 glyphshow +101.969 0 m /uni01A9 glyphshow +112.078 0 m /uni01AA glyphshow +117.453 0 m /uni01AB glyphshow +123.734 0 m /uni01AC glyphshow +133.516 0 m /uni01AD glyphshow +139.797 0 m /uni01AE glyphshow +149.578 0 m /Uhorn glyphshow +163.312 0 m /uhorn glyphshow +173.453 0 m /uni01B1 glyphshow +185.688 0 m /uni01B2 glyphshow +197.219 0 m /uni01B3 glyphshow +209.125 0 m /uni01B4 glyphshow +220.812 0 m /uni01B5 glyphshow +231.781 0 m /uni01B6 glyphshow +240.188 0 m /uni01B7 glyphshow +250.844 0 m /uni01B8 glyphshow +261.5 0 m /uni01B9 glyphshow +270.75 0 m /uni01BA glyphshow +279.156 0 m /uni01BB glyphshow +289.344 0 m /uni01BC glyphshow +300 0 m /uni01BD glyphshow +309.25 0 m /uni01BE glyphshow +317.422 0 m /uni01BF glyphshow +grestore +/DejaVuSans-1 16.000 selectfont +gsave + +110.68 153.734 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.6719 0 m /uni01C4 glyphshow +47.4219 0 m /uni01C5 glyphshow +68.2031 0 m /uni01C6 glyphshow +86.6719 0 m /uni01C7 glyphshow +100.047 0 m /uni01C8 glyphshow +112.641 0 m /uni01C9 glyphshow +119.953 0 m /uni01CA glyphshow +134.859 0 m /uni01CB glyphshow +149.641 0 m /uni01CC glyphshow +162.406 0 m /uni01CD glyphshow +173.359 0 m /uni01CE glyphshow +183.172 0 m /uni01CF glyphshow +187.891 0 m /uni01D0 glyphshow +192.344 0 m /uni01D1 glyphshow +204.938 0 m /uni01D2 glyphshow +214.734 0 m /uni01D3 glyphshow +226.453 0 m /uni01D4 glyphshow +236.594 0 m /uni01D5 glyphshow +248.312 0 m /uni01D6 glyphshow +258.453 0 m /uni01D7 glyphshow +270.172 0 m /uni01D8 glyphshow +280.312 0 m /uni01D9 glyphshow +292.031 0 m /uni01DA glyphshow +302.172 0 m /uni01DB glyphshow +313.891 0 m /uni01DC glyphshow +324.031 0 m /uni01DD glyphshow +333.875 0 m /uni01DE glyphshow +344.828 0 m /uni01DF glyphshow +grestore +/DejaVuSans-1 16.000 selectfont +gsave + +90.0078 134 translate +0 rotate +0 0 m /uni01E0 glyphshow +10.9531 0 m /uni01E1 glyphshow +20.7656 0 m /uni01E2 glyphshow +36.3594 0 m /uni01E3 glyphshow +52.0781 0 m /uni01E4 glyphshow +64.4844 0 m /uni01E5 glyphshow +74.6406 0 m /Gcaron glyphshow +87.0469 0 m /gcaron glyphshow +97.2031 0 m /uni01E8 glyphshow +107.703 0 m /uni01E9 glyphshow +116.969 0 m /uni01EA glyphshow +129.562 0 m /uni01EB glyphshow +139.359 0 m /uni01EC glyphshow +151.953 0 m /uni01ED glyphshow +161.75 0 m /uni01EE glyphshow +172.406 0 m /uni01EF glyphshow +181.656 0 m /uni01F0 glyphshow +186.109 0 m /uni01F1 glyphshow +208.859 0 m /uni01F2 glyphshow +229.641 0 m /uni01F3 glyphshow +248.109 0 m /uni01F4 glyphshow +260.516 0 m /uni01F5 glyphshow +270.672 0 m /uni01F6 glyphshow +288.484 0 m /uni01F7 glyphshow +299.406 0 m /uni01F8 glyphshow +311.375 0 m /uni01F9 glyphshow +321.516 0 m /Aringacute glyphshow +332.469 0 m /aringacute glyphshow +342.281 0 m /AEacute glyphshow +357.875 0 m /aeacute glyphshow +373.594 0 m /Oslashacute glyphshow +386.188 0 m /oslashacute glyphshow +grestore +/DejaVuSans-2 16.000 selectfont +gsave + +138.602 115.719 translate +0 rotate +0 0 m /uni0200 glyphshow +10.9531 0 m /uni0201 glyphshow +20.7656 0 m /uni0202 glyphshow +31.7188 0 m /uni0203 glyphshow +41.5312 0 m /uni0204 glyphshow +51.6406 0 m /uni0205 glyphshow +61.4844 0 m /uni0206 glyphshow +71.5938 0 m /uni0207 glyphshow +81.4375 0 m /uni0208 glyphshow +86.1562 0 m /uni0209 glyphshow +90.6094 0 m /uni020A glyphshow +95.3281 0 m /uni020B glyphshow +99.7812 0 m /uni020C glyphshow +112.375 0 m /uni020D glyphshow +122.172 0 m /uni020E glyphshow +134.766 0 m /uni020F glyphshow +144.562 0 m /uni0210 glyphshow +155.688 0 m /uni0211 glyphshow +162.266 0 m /uni0212 glyphshow +173.391 0 m /uni0213 glyphshow +179.969 0 m /uni0214 glyphshow +191.688 0 m /uni0215 glyphshow +201.828 0 m /uni0216 glyphshow +213.547 0 m /uni0217 glyphshow +223.688 0 m /Scommaaccent glyphshow +233.844 0 m /scommaaccent glyphshow +242.188 0 m /uni021A glyphshow +251.969 0 m /uni021B glyphshow +258.25 0 m /uni021C glyphshow +268.281 0 m /uni021D glyphshow +276.625 0 m /uni021E glyphshow +288.656 0 m /uni021F glyphshow +grestore +/DejaVuSans-2 16.000 selectfont +gsave + +118.953 95.4688 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.0781 0 m /uni0225 glyphshow +65.4844 0 m /uni0226 glyphshow +76.4375 0 m /uni0227 glyphshow +86.25 0 m /uni0228 glyphshow +96.3594 0 m /uni0229 glyphshow +106.203 0 m /uni022A glyphshow +118.797 0 m /uni022B glyphshow +128.594 0 m /uni022C glyphshow +141.188 0 m /uni022D glyphshow +150.984 0 m /uni022E glyphshow +163.578 0 m /uni022F glyphshow +173.375 0 m /uni0230 glyphshow +185.969 0 m /uni0231 glyphshow +195.766 0 m /uni0232 glyphshow +205.547 0 m /uni0233 glyphshow +215.016 0 m /uni0234 glyphshow +222.609 0 m /uni0235 glyphshow +236.094 0 m /uni0236 glyphshow +243.734 0 m /dotlessj glyphshow +248.188 0 m /uni0238 glyphshow +264.156 0 m /uni0239 glyphshow +280.125 0 m /uni023A glyphshow +291.078 0 m /uni023B glyphshow +302.25 0 m /uni023C glyphshow +311.047 0 m /uni023D glyphshow +319.969 0 m /uni023E glyphshow +329.75 0 m /uni023F glyphshow +grestore +/DejaVuSans-2 16.000 selectfont +gsave + +79.4297 76.8125 translate +0 rotate +0 0 m /uni0240 glyphshow +8.40625 0 m /uni0241 glyphshow +18.0625 0 m /uni0242 glyphshow +25.7344 0 m /uni0243 glyphshow +36.7188 0 m /uni0244 glyphshow +48.4375 0 m /uni0245 glyphshow +59.3906 0 m /uni0246 glyphshow +69.5 0 m /uni0247 glyphshow +79.3438 0 m /uni0248 glyphshow +84.0625 0 m /uni0249 glyphshow +88.5156 0 m /uni024A glyphshow +101.016 0 m /uni024B glyphshow +111.172 0 m /uni024C glyphshow +122.297 0 m /uni024D glyphshow +128.875 0 m /uni024E glyphshow +138.656 0 m /uni024F glyphshow +148.125 0 m /u1F600 glyphshow +164.812 0 m /u1F601 glyphshow +181.5 0 m /u1F602 glyphshow +200.203 0 m /u1F603 glyphshow +216.891 0 m /u1F604 glyphshow +233.578 0 m /u1F605 glyphshow +250.266 0 m /u1F606 glyphshow +266.953 0 m /u1F607 glyphshow +283.641 0 m /u1F608 glyphshow +300.328 0 m /u1F609 glyphshow +317.016 0 m /u1F60A glyphshow +333.703 0 m /u1F60B glyphshow +350.391 0 m /u1F60C glyphshow +367.078 0 m /u1F60D glyphshow +383.766 0 m /u1F60E glyphshow +400.453 0 m /u1F60F glyphshow +grestore +/Cmr10-0 16.000 selectfont +gsave + +248.008 61.4844 translate +0 rotate +0 0 m /i glyphshow +4.4375 0 m /n glyphshow +13.3281 0 m /space glyphshow +18.6562 0 m /b glyphshow +27.5469 0 m /e glyphshow +34.6562 0 m /t glyphshow +40.875 0 m /w glyphshow +52.4375 0 m /e glyphshow +59.5469 0 m /e glyphshow +66.6562 0 m /n glyphshow +75.5469 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..61a6802918dd --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/multi_font_type42.eps @@ -0,0 +1,17983 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: multi_font_type42.eps +%%Creator: Matplotlib v3.11.0.dev2222+g4230aa142, https://matplotlib.org/ +%%CreationDate: Fri Apr 3 00:28:30 2026 +%%Orientation: portrait +%%BoundingBox: 0 0 576 432 +%%HiResBoundingBox: 0.000000 0.000000 576.000000 432.000000 +%%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 +/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-0 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 133 dict dup begin +/.notdef 0 def +/.null 1 def +/nonmarkingreturn 2 def +/Xi 3 def +/dotlessi 4 def +/oslash 5 def +/Delta 6 def +/Theta 7 def +/germandbls 8 def +/Phi 9 def +/Sigma 10 def +/Upsilon 11 def +/Omega 12 def +/OE 13 def +/Lambda 14 def +/Psi 15 def +/ae 16 def +/Pi 17 def +/oe 18 def +/Gamma 19 def +/Oslash 20 def +/comma 21 def +/nine 22 def +/M 23 def +/Z 24 def +/quoteleft 25 def +/dotaccent 26 def +/g 27 def +/t 28 def +/exclam 29 def +/period 30 def +/semicolon 31 def +/B 32 def +/O 33 def +/quotedblright 34 def +/ring 35 def +/i 36 def +/v 37 def +/ff 38 def +/numbersign 39 def +/zero 40 def +/equal 41 def +/D 42 def +/Q 43 def +/k 44 def +/x 45 def +/hungarumlaut 46 def +/ffl 47 def +/percent 48 def +/two 49 def +/question 50 def +/F 51 def +/fl 52 def +/questiondown 53 def +/caron 54 def +/S 55 def +/m 56 def +/z 57 def +/quoteright 58 def +/four 59 def +/H 60 def +/U 61 def +/bracketleft 62 def +/acute 63 def +/AE 64 def +/b 65 def +/o 66 def +/polishlcross 67 def +/parenright 68 def +/six 69 def +/J 70 def +/W 71 def +/bracketright 72 def +/d 73 def +/q 74 def +/tilde 75 def +/plus 76 def +/eight 77 def +/L 78 def +/Y 79 def +/f 80 def +/breve 81 def +/s 82 def +/space 83 def +/hyphen 84 def +/colon 85 def +/A 86 def +/N 87 def +/quotedblleft 88 def +/h 89 def +/u 90 def +/dieresis 91 def +/slash 92 def +/C 93 def +/ffi 94 def +/P 95 def +/j 96 def +/cedilla 97 def +/w 98 def +/dollar 99 def +/one 100 def +/E 101 def +/dotlessj 102 def +/exclamdown 103 def +/fi 104 def +/R 105 def +/l 106 def +/y 107 def +/hardspace 108 def +/ampersand 109 def +/three 110 def +/at 111 def +/G 112 def +/T 113 def +/grave 114 def +/a 115 def +/n 116 def +/emdash 117 def +/endash 118 def +/parenleft 119 def +/five 120 def +/I 121 def +/V 122 def +/c 123 def +/circumflex 124 def +/p 125 def +/asterisk 126 def +/seven 127 def +/K 128 def +/X 129 def +/e 130 def +/macron 131 def +/r 132 def +end readonly def + /sfnts[<00010000000d0080000300504f532f321350119e00004b940000004e636d61700ed90eff000000dc000000ea6376 +74204d184f4a000001c8000000da6670676d0211c261000002a4000001d8676c7966725a810d000008e40000405668656164 +5f1a847b0000047c00000036686865610d5f069100004b7000000024686d7478ab9523030000493c000002146c6f63619a5d +a8d6000004b40000010c6d617870017400cb00004b50000000206e616d651c3b34c20000077000000174706f737474c85e0b +000005e80000018670726570ef569262000005c00000002800000001000300010000000c000400de00000004000400010000 +007effff00000020ffff00000001000400000053001d0022002700630030006d003a00770044007e004c00150054001e005c +002800640031006e003b00780045007f004d00160055001f0067002900350032006f00560020005d002a006500330070003c +007900460080004e001700570021005f002b006900370071003d007a00470081004f0018003e00580048007c001a00190073 +0041007b004900820050001b005900240060002c006a003800740042007d004a00840052001c005a00250062002d006b0039 +00750076002e004b000000060008000e001d002b0042fe5afe73ffd30000037303a0057705a401cd00e100db00d500b000a8 +00a600a400980093008d007f006d006a0068005e00560052004e004a00480042003d003b003700350033002f002107fe07ee +05ec05c305b005a0057b0552050804df040803fe03e9031902fc02f402e302aa026d025a0227021f01e901c10185017f016d +012500ee00e100df00db00d900d500cf00c500c300c100be00ba00b800b400b200ae00a600a400a200a000960091008f008b +0087007f007d00790073006f006a0062005200480042003b00350021000040161514131211100f0e0d0c0b0a090807060504 +030201002cb200800043208a628a234266562d2cb22a0000435478b0002b58173959b0002b58173c59b0002b58b00a2a59b0 +014310b0002b58173c59b0002b58b00a2a592d2c2b2d2c2bb0022a2d2cb0022a2d2cb00162b0002342b10103254220462068 +6164b0032546206820b0044323612064b140408a545821212121b100211c5950582121b1000425204668b007254561b00051 +58211bb0054338591b6164595358232f23f91b2f23e959b0012b2d2cb00162b0002342b101032542204620686164b0032546 +206861645358232f23f91b2f23e959b0012b2d2cb00162b0002342b1010525423fe9b0012b2d2cb00162b0002342b1010325 +423ff9b0012b2d2c111217392d2cc12d2cb2000100432020b004438a45b003436169604460422d2c4520b0032342b2010205 +43764323438a23616960b004234218b00b2a2d2cb0002342184569b0406120b000515821b0411bb04061b0005158b0461bb0 +485959b00523424520b001234269b0022342b00c2a182d2c204568442d2cba00110005ffc0422b2d2cb2110500422b2d2c20 +20b102038a4223b0016142466820b0405458b0406059b00423422d2cb1020343114312173931002d2c2e2d2cc52d2c3fb014 +2a2d00010000000100003b6a6a965f0f3cf500030800000000007c259dc0000000007c259dc0ffa6fe000812060000000006 +0002000000000000000000000000000000690069006900690069006900690069006900690069006900690069006900690069 +006900a00110016401af01ea020e02b302f80336035903a70412046a04d104d105100550055005ea0632066e06bf075907b8 +0824085d085d0904096e09db0a2f0a2f0a9a0a9a0b210b9a0be50c1e0c5f0cad0cf60d180d180d180d710dbb0dbb0df60e72 +0eba0f230f450fab1007103b107e10fb1130117d11d211d2124e124e126612a112ee133613a013f314431443146b14da14da +15271583158315e8169716c6172817281766176617de180718651865190a19961a3f1abb1b031b031b7d1bd11be91c011c42 +1cc21ce81d301d851da41e061e731eba1f1a1f8a1fe11fe1202b401e072703220b1f080f04275d0e0d076a0c5d0755055123 +4a055d5d2b0d35008db8033c851d2b2b0002000000000000ff7b001400000000000000000000000000000000000000000085 +000000010002010200d700a100a801030089010401050106009f00b00107010800a0010900b1010a0091000f001c0030003d +00b600dc004a005700040011001e0025003200b500dd004c0059010b00060013002000270034004e005b00df010c00080015 +0022002900c100a200e100360050005d00b70017002b0038003e008d009000450052010d000c0019002d003a004000470054 +00d9000e001b002f003c004900db005600030010001d0024003100b4004b0058008e00120026010e0033004d00de005a0007 +00140028010f00a300c00035004f005c0110000900160023002a003700430044005100b300b2000b0018002c0039004600d8 +0053000d001a002e003b004800da005502586905546865746103506869055369676d6107557073696c6f6e064c616d626461 +035073690250690547616d6d610266660366666c0c706f6c6973686c63726f73730366666908646f746c6573736a09686172 +647370616365000000000007005a000300010409000000be00000003000104090001000a00be0003000104090002000e00c8 +0003000104090003002000d60003000104090004000a00be0003000104090005001a00f60003000104090006000a01100043 +006f0070007900720069006700680074002000280043002900200031003900390034002c00200042006100730069006c0020 +004b002e0020004d0061006c00790073006800650076002e00200041006c006c002000520069006700680074007300200052 +0065007300650072007600650064002e00300031003200420061004b006f004d006100200046006f006e0074007300200043 +006f006c006c0065006300740069006f006e002c0020004c006500760065006c002d0042002e0063006d0072003100300052 +006500670075006c006100720046006f006e0074004d006f006e006700650072003a0063006d0072003100300031002e0031 +002f00310032002d004e006f0076002d003900340043006d00720031003000030056000004fe0577000f001b0029004a4042 +27220225140b011a080209201c0225161e0c040816120218100216141a14060e020208160009100703041f0e0218016a1714 +12051a011c01026a12110c06022b0f032b31002b2a3033033316171e01332132363736373303011133152135331123352115 +031321132326272623212207060766103b0518088864021065870818053b10fc2f3b02a43b3bfd5cf8110472113c05150fe3 +fdfce30f1505015e9d1b080606081b9dfea2022301686868fe986868020c0148feb88c180c0c188c000100acfe7301a400e1 +00180020401806010e0f08090107010416070b00026b11060405011a0f032b31003f2b301334373e013d0106232226353436 +3332161514060706232226cb084a5221312f42422f493e5b5308050a14fe8f090847ba671921422f3040875272cd52041200 +00020056ffd303a805540028003a003b403300010b02093225130c00080801220126290b140602231c090007030408014e18 +2f010500014e251f010650370f0006033c0f032b31002b2b303716333236373e01350e0123222e0135343e0133321e021514 +02062322263534363332161514062301323e013d02342623220e0215141616e7388b4e87252b1823835577bb6470c67e7ca7 +582374e7a379a8392a29393a280108546b305a7f5165300d166256426a4d57c592536a81d3777bd57d87d5ee749efeb7dc72 +732a39392a283a019c71a85327089af24776864f74a47d00000100480000070c057700250037402b211b0b03131e0917090f +0c080c000916100701041225180b0a041b220956131b0005692204000602270f032b2b2b3f3f3f3f3f2a3033353235113423 +3521321709013633211522151114331521353235110106232227011114331548d3d30183190801be01be08190183d3d3fdac +d3fe0809191a09fe0ed34879042d414817fb790487174841fb9b4148484104a8fae61717050afba07948000100730000047b +0577001e0033402b1d0c02071509130107220e0c0108050115200009010702041c1413110d0c0b060509351d03010501200f +032b31002b2b3033223d0134370121220e0115231321321d01140701213236373e02373303891604031cfee090bb5f3c1703 +b41702fce3012d6dae3b292e0e073c23171c080404f04cae9301d517180904fb13283a297c7462fdd5000001008f031f018d +058d001b001f401714010f160001060104090c190c026b12031005011d0f032b31003f2b3001222635343e01373633321615 +14070e0215141736333216151406011d4a442c533608040a1509314a26021d39313f40031f87524e91832f04130908092b75 +8642150a2741302e4200000100ac0479018d055a000c001840110a0f030c000801044807000005010e0f032b31002b301334 +3633321e01151406232226ac442d1c361e422e2d4404e92d441e361d2c44440000030039fe5a03e103a0003b004b0057005b +4052210802514c0914011a11021f0151260f0a15082a01264c28100603012f194809010740263807000704042a014e3c0917 +011f1d02633444110521110259244e0106542c0803040a0602633c00110603590f032b2b31002b2b30173436372e01353437 +2635343e023332173e0133321615140623222635343722071e0115140e01232227061514163b01321e0115140e0123222626 +37141e0133323e013534262b01220606013235342623220615141616396a49292b3d5e3762783f7a612a733e2c3826191a26 +196a4c252d609d53705d1d4736a87ac48598d35a5bd49873709e46459e6fc48ca82f4f30011bae4a64644a1c4ca0496d171f +5e35604a5c774070522b472d313f2c19262619260f49256b35578b4d3d283236512c84795a773535775a455d2d2d5d456b3f +2d5101d8f86b8b8b6b446e4600010027ffe902a804ec001b0037402e1401010f090a0103010122080a03080f241909000702 +04070a016a151201050c01030106015b07000d06021d0f032b31002e2b2b303711233532363533112115211114163332363d +013315140e01232226d1aa867e3b0121fedf394a463e3b2f5c427b8ff6023535fa92fe8748fdcf5580874e797d407d509300 +000200ac0000018d05ba000c001d002040181b01030f0a09100701041216010f014807000a05011f0f032b31002e2b303734 +3633321e0115140623222613033534363332161d010314062b012226ac442d1c361e422e2d445454452c2d43520c0619050b +712e421e361c2d4444015403b00c2b3b3b2b0cfc50070c0d000100ac0000018d00e1000c00184011030f0a09000701044807 +000005010e0f032b31002b3037343633321e01151406232226ac442d1c361e422e2d44712e421e361c2d4444000200acfe73 +019303730018002600294021240f1d0a000805010d0f0709010702041607190a000321016b1005050501280f032b31003f2b +30133437363d010623222635343633321615140e01070623222603343e0133321e01151406232226cb048f1e232f42422f47 +2f23473106090a141f1e351e1d351e412f2e43fe8f09049bd10a12422f30408356488c86350612047d1d342020341d2e4343 +00030046000005350577001700250036003a403432010622080c02080f0126272501061c010122000908070304070102124c +132000050f014d0c2c04062601551804080603380f032b2b2b30333532351134233521321e0115140607321e0115140e0123 +2514163321323e0135342e0123213521323e0235342e022321220e011546d3d302f168d48bcd8959bc7885d46bfe5a323601 +04508950427b4ffe7701333e6d572f23445c35fefc25291a484104654148519f6c7da91a62a45c70ac5d892c15548d504e95 +60362d556b3c3562502d061d1e0000020073ffd305c505a40011002a0023401c2024090c000815240009000702044a0e1b00 +054a27040006022c0f032b31002b30052224023534123e0133321e011215140204011e0133323e0137361110272e01232206 +070e0215141616031dc3fec9b065b5fe9291ffb662b0fec8fdec3cb068438169257a7a3cb36364b43c30351615392dcf0157 +bd8c0112d47c7dd6fef691bdfea9cf010a5e6f365e39b801420127ac566868564397a2575db1aa0000020044031f02cf058d +001a00350034402a2a012401220702090f0f0c0b080104331827221d1b042013096b2e2000050c00026b1305040602370f03 +2b2b31002e2e2b301334373e013534270623222635343633321e0115140607062322262534373e0135342706232226353436 +33321e01151406070623222662084c56021d392e42422e33401b615408040b14018e084e54021e382f42422f32401b615308 +050a14033b090842c066150a27422f304044662f71d64a04120a090844bd67150a27422f304044662f71d54b04120002003f +000001fe055a000f001c0025401c1a0f130c000801040a0a0009170f02100901035c0a051405011e0f032b31003f3f2b3033 +35323635113426233525111416331501343633321e011514062322263f465a3d5a01274e41fe98442c1d361e442d2c444816 +2b022f4f244816fd002b164804e92d441e361d2c444400010027ffe904100373001d002140170c1c09140a060a130f0c0b09 +07063715050105011f0f032b31003f3f3f2e3021012e0123352115221514171b01363534262335211522060701062b012201 +f4fed5134f4001ae7302e6cf063b2801543f5f1afeec08190f1902f026154848310804fdbe020a1011272d48483a39fd4817 +00020073fe730635058d0047004b004f4044271e024b2e021f130c0a064930024237021f0a030a06020445073b07220c180c +340107014b4a49484241403e38302f27261e1d1c140c0b030200162e2b100b05014d0f032b31003f3f3f3f2b300134371321 +22263534363321132122263534363321133e013332161d010321133e013332161d0103213216151406232103213216151406 +232103062322263534371321030623222601211321015602a6fe9c11161611017d51fe321116161101e7ac03150f1118a801 +81ac03150f1118a8016610151510fe815201d110151510fe17aa0b1e111802a6fe7faa0b1e11180114018251fe7ffe9c0404 +026c1a0f1118013c18110f1a027f0d11181108fd94027f0d11181108fd941a0f1118fec418110f1afd811e18110404026cfd +811e1802d7013c0000020050ffd303ae0554000f00200023401c1827070c00081027000900070204550c140005551c030006 +02220f032b31002b300522021134123633321e021514020627323612353402262322060215141e01160200fbb541c1ae87ac +5a2141beaf72701a1a6f7374701a0b306b2d019d011db2013adb84d1ef83b0fecdd735ea011ca09a0104d3d4fefd9a72cad7 +930000020073011005c502f0000d001b002040191f150e00061f07000006020418011101320a030a05011d0f032b31002b30 +132226353436332132161514062301222635343633213216151406239a1116161105060f16160ffafa1116161105060f1616 +0f01101a0f111818110f1a018e18110f1a1a0f11180000020044000005a8057700120028002a402424010622080c02081701 +0122000908070204070102124c0d1d00055313040006022a0f032b2b2b30333532351134233521321e011215140e02232514 +163b013236373e01353426272e012b01220e011544d3d302f38ce8a4595aa9e787fe983236cb69bd3e412c2c413dbc6bcb25 +291a48410465414879caff008682f5c572892c155b5156d58f95e058575d061d1e0000030073fe7305d105a400260031004e +004f404539012c12094424090c000827362c00064d1b02270112250009180715102007000704042509392925033e2f091d01 +12014c0e3e14054d016b2f3201064c4a04000603500f032b2b31003f2b2b30052224023534123e0133321e01121514020607 +1e01333236353436333215140623222e0227062732372e0123220615141627343e01333216173e03353426272e0123220607 +0e011514121726031dc3fec9b065b5fe9291ffb66263bd7e2752494d6e0f07177383485e311c0b5a665c56134f5031444176 +2c4f2f596828445c331739443bb66567b53c463794ad162dcf0157bd8c0112d47c7dd6fef6918dfef4d43b5b656a4c070c1b +93f6476d903b1f3b2f586949303443772d50317362338b99ab568efa64596d6b5b66fa8cdafe9b4a2a000001003500000417 +058d002a004140392524230c0412010915011222140a0208291f1c031e01012200090a0702040b0c211f1d1815130f07122a +010a010226015d0b051505012c0f032b2b3f2b2b30333532363511342e0123352511253635342623352115220f01011e0133 +152135323534270307151416331535465a213e41012f011329221801818b8b920105364954fe684625c57d5b4548162b0433 +37310b4816fc34f1272118194848797ffe8e4d2c48482b1f2f01186ce42b16480001001900000421037300330044403c2c2b +1211040901091a011b180c0309220b0a0a08322623032501012200090a070204332f2c2b29261f1b191512110f0c0a051035 +2401010501350f032b31002b2b30333532363f01032e0123352115220615141f0137363534262335211522060f01011e0133 +152135323635342f0107061514163315194e8a30baf224554d01aa1b2f06a47b19211b01794f8b30a2010627544efe56192e +06b893172217483d3ced013b2d1548481817080bd59e1e1e192448483d3ccffea62d14484818170909f4bc1a221924480002 +01020419035c059a000a001500204016150a0e0c030c15140b0a0907063e1200010501170f032b31003f3f2e2e3001133633 +321e011514070325133633321e011514070301026f123113281710bf01216f123113281710bf0433013334142612151afefa +1a013334142612151afefa0000040073ff8d063506000029003600470054005c405324070303311a02014f4802091601271f +310806271a0500063f0e021b2a4f010627012648370206040424014c5202012d34020922016a434c040503015f523b100607 +016a092d010600015f3412100604560f032b2a31002b2a3005343701062322271615140e0223222e0135343e013332171633 +32363736333216151407010623222613323635342e0123220615141601222e0135343e0133321e0115140e010627323e0135 +3426232206151416011d0603a07b94a093291f406544608a45458a604c3fa5e279d2430a16121706fbdf091511188565682b +5c4666424403ef608a45458a605978371f3f6545455e2a68656642444a0c09056645536279428d7d5180c05d5bc1803da26b +641016130b09f9d70d1a0355f17743ab79e38681e5fc9180c15d5bc18087be57428c7f51367baa4376f0e38582e400010066 +00000398055400320044403b2e2918030d2b091210020d22200c0408310103012b140009110702042901091509310132302e +034f240909051b012a100303481501030602340f032b2b31002b2b3033353437013e0335342e012322060736333216151406 +23222635343e0233321e0115140e020f0133323637363733036604013e485a58333e7b57598e1d080e2e41412e30413a6d89 +4d75ca764e7abe1ee8c591c30618193c3a37050601604e6a8a8f5054995c6b55023e312f41432d4d87693863b57959a083a6 +1cdf05051aa3fe93000200730000035205a4000c003a0035402d221b021803091827290c00083801030f0a0910070204552d +1400050e0148070001061b014e1f250106033c0f032b31002b2b3025343633321e0115140623222613353412373e0135342e +012322060733321615140623222635343e0133321e01151406070e011d0114062b0122260156442d1c361e422e2d4454625a +1e1c265e554f89260c29393a28283a639e5361b5753833758d0c0619050b712e421e361c2d44440154688601025d20593154 +602c403f392a283a3a28547f44337e663c6f2452ec8464070c0d0001003f000004e105770026003b40321b01061609100106 +22080c02080a01221622100602041d0009090701031226011d016a1c1a06052301511504080602280f032b2b3f2e2b2b3033 +353235113423352113232e032b01220e01151133323e0135331123342e012b01111421153fd3d30469393b0e2f5a9784bb25 +291a916962253b3b256269910106484104654148fe2b81955522061d1efdf1256269fdd9696225fdf141480000020073fe5c +03520400002c00390036402c1c013719090f3037000619272a07000702040c23091c014e26200105100148342d0106551500 +0006033b0f032b31003f2e2b2b30173436373e023d0134363b0132161d011406070615141e01333236372322263534363332 +1615140e0123222613343633321e01151406232226732e2e456135090719070b4b4a2b1247495ca92e0a293a3a29283a7ab8 +5991c3e3442d1c361e422e2d448d3b6f25388ea45864060d0c076882fe653a704b5d383c433a29283a3a285e7f3a8a04a92d +441e361d2c44440000010073ffd303fe05a400490045403c3627131204052f0a091a011c012f23200c0c08440148010a2240 +091207020444361c1312050e070924015e3c0e0105330116016a07011206024b0f032b2b31002b2b301711343b0132161514 +1633323e0135342e0127252e0135343e0133321737363b0132161511142b012235342e01272623220e0115141617051e0315 +140e0123222e012707062b0122731219060af9ca477843325e3bfef684a76cb76acd795406080e060b111813233e2463a346 +76466d58010a42754e2c66b96e448e78315606090c121d01de100a06c9dd5285473e75560e4123d9876aba6c8b85060908fe +251212347c722464477a43588f174110536e87486fc5781e3e3187060001003d000006850389003f0047403c0f0b02110c02 +37012627140a0e0801042f091e090a0a00091d011f015b182314052e01300111015b2a3415063f010a01020b015b3b051506 +03410f032b31003f3f3f3f2b30333532363511342e01233525153e013332173e0133321e0115111416331521353236351134 +2623220615111416331521353236351134262322061511141633153d465a213e41012929a15fec29299e5e5d7f405b45fe2b +465a3a5a769a5a46fe2b465a3a5a77995a4548162b022f37310b4816c85870c0566a3c7b5dfe142b164848162b01e6677ebe +79fe6c2b164848162b01e66481be79fe6c2b164800010039000003350373001f0033402b1e0d02071709150107260f0a0108 +050117250009010702041d1615130e0d0c060509391e03010501210f032b31002b2b3033223d0134370123220e0215231321 +32161d01140701333236373e01373303501706023cb8577149213b1702ae090d04fdc3c459772a271d083b23171008060308 +163d6b5e01520d0a0c0608fcf9162a278461fe79000100ac031f01aa058d001a001f40170701090f0f0c01080104180c0002 +6b13050405011c0f032b31002e2b301334373e013534270623222635343633321e011514060706232226cb084e54021e382f +42422f32401b615308050a14033b090844bd67150a27422f304044662f71d54b041200020039000003c5055400160019002f +4026180102160122080a0a0601041905110917010212100a02070112011901570c161d05011b0f032b2b3f2e2e2b30133501 +363b013215113315231514163315213532363535252111390279070e1e17c9c9784ffdcc4f78fe2701e501524803b00a17fc +5d48c92a174848172ac94802d5000001003f000005be05770023003a402f220d1f000601041a09120c080c00091913070104 +12231b1109040e0c091e0151160e02052001510c04080602250f032b2b2b3f3f3f3f2b303335323511342335211522151121 +113423352115221511143315213532351121111433153fd3d30265d3025cd30264d2d2fd9cd3fda4d34841046541484841fe +0e01f241484841fb9b41484841022bfdd54148000001003fffd305be05770022002d40240d221f0900070104160c050c1704 +02121506021209096819120005510900000602240f032b2b2b3f3f2b3001113423352115221511141e0133323e0135113423 +352115221511140e02232226260112d30265d33f957875b260d301edd2437fac6188f39001cf031f41484841fce972cb7f7b +cc7502df79484879fd195fb6935488ea000100f2fe00020a06000007002040191f02030006001f0507000802040703026705 +01100501090f032b31002b301311211523113315f20118c6c6fe00080052f8a4520000020035ffe9042d058d0019002a0033 +402a080127270c0a040818011d26150910070204070c000955112100050601191807035b1a000506022c0f032b31003f3f2b +303311342e01233525113e0233321e0215140e012322262707371e0133323e013534272e0223220607d5213e41012f225b68 +365c9d744179d17d4e9230465a22804e6a83342d1445552f528c2904bc37310b4816fd7f26391e4a82a95a7cd67f50427bc9 +4b5f7aba67ad5a284427574900020039ffe903c50396001000240023401c1b26090a00081124000900070204540d14000554 +2104000602260f032b31002b3005222e0135343e0233321e0115140606273236353426272e02232206070e01151416160200 +7bd27a437da6617ecf787ad17aa46e162517474f2a40732626152879177dd27c5eae894d85df7e7bd37d3ceeb86787372233 +1b3a363a8b6073b77c0000010073fe0002540600001b0016400f0e000a0202126014060005011d0f032b2b2e2e3013223534 +3700111001263534363b013217161a0115140a0106070623851204015efea6080b0713060493c45b316ba4720406fe001209 +040156028b028b0152050c070b0474feb4fe88c491fee7feefe75a0400020056ffd303a80554002c00420040403817011a24 +091a25090c0008100121013626240a14082d23000900070304170150293201054e0d1300063c013f0121014e3a0519060344 +0f032b31002b2b3005222e023534123633321e011514062322263534363b012e0123220e04153e0133321e02151406062732 +3e0235342e0123220e0115141714060714161602007faa5d247ef5a8467945392a283a3a280b1a5f333e6954381f08248453 +5b966c396bc27b4f602d0b166265536b3102010124662d87d7ec79a20146d63567492a393a29283a2523365c6f8e7c5e546b +4a83a85678d980414877795874a47d70ab4f1b0e03040358b47c0001004cffd303b8057700230028401f0327150900070104 +1c0c0c0d0152100810050b010001472019110602250f032b31003f2e2b30371e0133323e013511342135211522061511140e +0123222e0135343633321e0115140623ba257643425b2dfeee0268455871b35f539861443321361f44327334375b873f03c5 +414848162bfc33629854437f5433441f3820324400010025ffd30812057700300039402f211202221f131007050422060c0a +0801042b190b03132f092809201c19181513110c0b0a070b2c2205010501320f032b31003f3f2a2b3005012e012335211522 +1d010901272e0123352115221514161509013635342623352115220701062b0122270901062b0122027dfe5e105c4a0225ac +014701172f105c4a0224ae040146013302723e01b6a226fe7007170f1707feaefeac07180e181705052b164848370afc1003 +5e922b16484837030c02fc1703b8060d3630484879fb3316160413fbed160001002dfe00014606000007002040191f060300 +06001f010700080204050102670703040501090f032b31002b3013353311233521112dc7c70119fe0052075c52f800000002 +0044ffe9043b058d001c002e003d403317012820090b012827080a04081a01000120261909120702041809120c1801110124 +010c015b12191705552c04000602300f032b31003f3f2b2b3005222e0135343e013332161711342e0123352511141e013315 +05350606251e0133323637112e0223220e0115141601f479c86f79d07d4b8631213d41012f213d41fecb3592fee423754555 +8e2318495b336b8234111783d6787cd57e3f3801aa37310b4816fb2d36310b4817813d44c94350624e01eb2d472679bc6752 +7a0000020044fe73043b0389001b002b0034402c110114012325160a0c0805011c2608091007020400071b01010120151403 +5b1605150655280d0006022d10032b31003f2b300135323635110e0123222e0235343e013332161737331114163315013236 +37112e0123220e02151416160266465a3092505c9e754178d17957942c49365a45fdc55b8f2215845c466e49243a78fe7347 +182a017b404e4c82ab587ad77e6252b4fb732a184701ac795c016862904a7c904052c186000100aa04930354055800130025 +401e030111010b1c090c0a08010113011b070d0a0602043c0a00000501150f032b31002b3013373633321e01333237170706 +23222e01232207aa3b5050275d5d27524c293b514f275d5d27524c04b6465c2e2e5c23455d2f2e5d00010073ff5605c504aa +001f0026401e06011f011f0f160a0601041b0b1303021217011e01670e070a0501210f032b2b2e2e2b301322263534363321 +1134363332161511213216151406232111140623222635119a11161611025a18110f1a025a0f16160ffda61a0f111801d71a +0f0f1a025c10151510fda41a0f0f1afda410151510025c0000030056ffd303a80554001e002e003c0043403a302f2b2a1303 +0637230937250b0c000823231b09000702042b2a02333b0964172600051301660f3304060301663b071006641f000006043e +0f032b2b31002b2b3013343637272e0135343e0133321e0115140e0107171e0115140e012322262637141e0133323635342e +0127250e010613173e0135342e0123220e01151456a27f4c465867ab615ba96d41714075516377c46d6ac57b6f59925077c2 +1f3722feed406b3e8df8566e4d7c473e7e5201377bbd3f312e9954629e5a4a8a5f45765e214b35ac5f6fb66456a36b51864c +8b73274d3f14b22268820229a0328e59457340305f4060000001003f000004a8057700160024401c10010122000908070104 +15080c150907010412510c04000501180f032b2b3f2e2b303335323511342335211520151114163b01323e013733033fd3d3 +0298fefa32369e99a645123b394841046541484841fb9b2c1570c1a0fde700010017000005e705770021002f402718011916 +0b0308220a0c0a080104100009211917130d090107120b011001531e04050501230f032b2b3f2e2b302135323511012e0123 +3521152215141709013635342623352115220607011114331501cfd3fe521e6c5302418f04017201520d472c01bc508927fe +73d3484101a602c3291448482f040cfd9d022b131629254848393cfd75fe5a41480000010042000002e305a40028003d4034 +19011b070914011b270e0c0408200122010522070a0a0802040009282219035211170106070102050120015c24080706022a +10032b31003f2b2b3033353236351123353335343e023332161514062322263534372623220e011d01331523111416331542 +455a9d9d375d7941456f3527273737211a3c552aece5784e48162b02a248f54273563152442735352740160b557a3cf148fd +5e2a174800010044ffe902e103960040004c4042302f240f0e0604072908091701190129291d0a0c083b013f010826390912 +0702041a0a3b302f190f0e060b2c09211a0265340b010501010601652c13030602420f032b2b31003f2b2b301711343b0132 +17123332363534262f012e0235343e0133321737343b0132161511142b01223534262322061514161f011e0215140e022322 +2707142b01224412190c0439db61836646894571485f9858694e3b0a0f060a101912776b5c8761418b467947335b7c44805b +4b0b0c1206014e1010fed7585c425d111b0f3e67445a73333833050b06fef413136b8244533949101a104c74494a6d482256 +510500010017017b023501fa00030017401019020000060104400301000501050f032b31002b301335211517021e017b7f7f +000200ac0000018d0373000c001a0022401b180f110a0008030f0a090007020415010d014807000a05011c0f032b31002b30 +37343633321e0115140623222611343e0133321e01151406232226ac442d1c361e422e2d441e351e1d351e412f2e43712e42 +1e361c2d444402be1d342020341d2e43430000020042000005bc05ba001c001f00314028221e1500061b100d030f01012200 +090a0702041f071f1e1d1c181514131009310e01010501210f032b31002e2e2b303335323701363b013217011e0133152135 +323d0103210306151416331503210342b72a01ae061b1a1b0601c1136b50fdc5aa6ffe0f5c0261382301c1e1487904e31616 +fae52b164848370a0140fef8070e3331480210028e000001003f000005be0577001f003240261b0b1809100c080c00091107 +0103121f0f0a030c1c091a0169130c0105691c04000602210f032b2b2b3f3f3f3f2e2e303335323511262335213217011134 +2335211522151114062b01222701111433153fd3439001880a0402d5d301e7d21005190a04fca4d3487904620c4808fbd503 +7279484879fb5c060c0804f2fbc779480002012f031f03ba058d001b00370035402b32011c013013020f15000b060104250c +080c19130d0b041f11093528026b2e1f10056b1103000602390f032b2b31003f3f2b3001222635343637363332161514070e +021514173633321e0115140621222635343e0137363332161514070e021514173633321615140601bc49445f5508050b1308 +314c25021e3820331e41015e4a442c533608040a1509314a26021d39313f40031f875271d44c04130909082b788342150a27 +1e32212f4187524e91832f0413090a072b758642150a2741302e42000001003d0000044c058d0028003340290c0120270f0a +0408010418090b0c0009170119015b121d140528010a01020b015b24051506022a0f032b31003f3f3f2b3033353236351134 +2e01233525113e0133321615111416331521353236351134262322061511141633153d465a213e4101302b9a5d8e8f5a46fe +2b465a3a5a77995a4548162b043337310b4816fd405567888cfe142b164848162b01e66481be79fe6c2b16480001003dffe9 +044c03890023003240281e0121010c261d09120701041c09160a070a1c0115011d015b1610150506015b0700040602250f03 +2b31003f3f3f2b303711342e0123352511141e013332363511342e0123352511141e01331505350e01232226dd213e410136 +174b526e82223d410135213e41fed126885293adf401c437310b4816fd6b50592cb875016c37310b4816fd3136310b4817ad +4d607d0000010073fe00038b0600000f0013400b0d06380a00000501110f032b31002e2e30133437013e013332161d010106 +232226730202c804140d1217fd380c1b1118fe29060207b60c0d161308f84a19180000010073ffd3055205a4003a0038402f +302a0b033203091c011f013222230c0c080322120900070204301f0208380927016a0d0808054a38170006023c0f032b2b31 +002b2b30251e0133323e0235343b013215140e02232224260235341236243332161737363b0132161511142b012235342e01 +2726232206070e0115141601d346d2715fa279411219105296c36a93fef9c36d6dc301079369c048770c020f060a1025132f +4930739571cf474b3a3adb59674b86aa5e10146bc7975477cf011093930110d0755b53a8060a07fdd712123b92833270665a +60f58b8bf60000020044000004fe0577001500230032402a1f010622080c02082417100006020400090701021215011b1209 +4a0c1b00051601511204010602250f032b2b2b3f2b30333532351134233521321e0115140e012321111433150321323e0135 +34262b01220e011544d3d302d970e09192de71feb8d3d90116718c4193abae25291a4841046541485cb07572ac59fe0a4148 +02bc418970a792061d1e0002ffa6fe5c01b2055a001c0029003d40310a0002270209270f200c00080227110700070204170c +0a0b0a1d0b02061a0924015d0d06080500014e1a140106022b0f032b2b31003f3f2e2b2b3013163332363511342e01233525 +11140e0123222635343633321615140613343633321e01151406232226292f3b513f284543013f4e864f59903a28283a238a +442d1c361e422e2d44fea817a560032237310b4816fc044f8d555850283a3a281f3406382d441e361d2c444400010025ffe9 +05a003730032003140252d1a0d031331092a09220a140a060a211d1a191715130e0d0c09070c312305010501340f032b3100 +3f3f3f3f3f2a3021012e012335211522151e01151b01272e0123352115221514171b01363534262335211522060703062b01 +22270b01062b012201c5fef712444101a6790101c5aa1b10464001947902cdba04492d015c3e5915f40718101807cfcf0a16 +0f1902e92d15484833030606fdd801e1472d154848330807fdbf020a100d2b3148484138fd4e17170248fdb8170000030073 +ff8d038b0600004f0058005f005c4053595841321e1914110f080a4018092a013c39025a0140212b0c1608500100014e0118 +2201090e070204280c4801543c3b034e2f350905504e41035a190003682a280a0622015e1e1411044e0b05030603610f032b +31003f2b2b300535222e013534363332161514062b0122272e01231e0233112e0327263d023436373e0133353315321e0115 +14062322263534363b013217332e0223111e01171e011d011406070e012315353e0235342e012727110e02151401db6da358 +3a28283a3a28020e070203010e577c423c3337331d723c362b8e3d4866a65c3a28283a3a28020e06051258793e546a2f3c3f +3b3732893b4573403e6f4b483f7544735f6cb76a283a3a28283a020101416c3b025611101a221c74a102024b8f3a2b485e5c +61a969283a3a28283a023d5a32fde11331303ca15704529c3b32485fa6095580434f754e13d5020c07497143c700000100b2 +0000035e055400110024401d0a010401220706110601040009110701031209015a0d04010501130f032b2b3f2b3033352035 +1106233532373332161511142115be01006aa2fb801d070d0100484104333348830b07fb474148000001003f000005370577 +002d0044403d1a0106151c01210102090f010622080c02080a012c012215211406260101220009080703042c09070104121c +016a1b19020522015114040806022f0f032b2b2b2a3033353235113423352113232e022b01220e01151133323e0135331123 +342e012b011114163b01323e023733033fd3d30486393b164faeaec925291a976867273c3c276768973236d98eaf6135173b +56484104654148fe2bb1a03c061d1efe0c236369fdda686423fdd72c152d69a794fde700000200acfe46018d04000010001d +001f40160f141b000601040e0618011101480b010a05011f0f032b31002e2e2b3013351334363b0132161513151406232226 +11343633321e01151406232226ac54090719070b52432d2c45442d1c361e422e2d44feac0c03b0060d0c07fc500c2b3b3b05 +0e2d441e361d2c44440000020044ffd305db05770030003d004940402f1e01032c170939010622080c0208100127322c0106 +17272409000703040009070102123001352d096a201a000510014a0c3504063101532d040806033f0f032b2b2b3f2b2b3033 +3532351134233521321e0115140e01071e011f011e013332363534363b013215140e012322263d0134262b01111433150333 +32363534262b01220e011544d3d3028373fdaa67a1545c8a0e1d142c4b403f0d0713142c533994d58e67f6d3d3dbaab2b0ac +7325291a48410465414853aa7656875b14208c5ab67b797746070b1b386b46938eb66692fde7414802d789a4a388061d1e00 +0001003f0000020e058d0010001a40120b0c000910010a01025c0b05140501120f032b31003f3f30333532363511342e0123 +352511141633153f465a213e4101305a4548162b043337310b4816fafc2b164800010027fe5c04100373002f002e40240227 +23070007010429111a0a0b0a1b19140c0505120e010a010001542d26130501310f032b2b3f3f2e2e2b30131633323f01012e +0123352115221514171b013635342e0123352115220607010e0223222635343633321e011514068d272f815246fecd134e41 +01ae7102e4cd061b2b1b01543f5f1afe9e1c4b6c404b7134261a29172cfeb01fc3ac02f026154848310804fdd001f8101319 +251448483a39fc9c426f476349263417281b213400030056ffd305d105ba003a00460053005940513d2f15100302061e2a09 +0a274e0c00074001210147011e22200a070835013b0137012a2233091a0703042f211f1b041210014a520927013d016a0d4a +11054003025f520601060201554300010603550f032b2b2b2b2b3013343f012e0135343e01333216151406071e03173e013f +013635342623352115220f010e01071e0133323e013533140e012322270623222626053237260227070615141616133e0135 +342e0123220e0115145652f4272b4783565e578b711d425565333d5b53330b583801c9b9474244714443874a3b673d3c4c82 +4dc6a9abc95aac6b0183a88d65bc3b52582c5f7b5d7814372e344520010a7352fe66d76951975fac685bc27b477e868a4148 +8d8b5a0c1730264848797076af504d653c653c4c88519c9c4c8f937d69011483545c9e458b5f032b67ac4f31624a476731b1 +00010056ffd303a80554004b00504047250119124400020b0302091f1c0219252c0c0408350124120b010603233d09000703 +041211021622094a3906000535014e311604061c0f00034b222801064748410006044d0f032b2b31002b2a30371e01333236 +35342e022b01223d01343337323e01353426232206073e0133321615140623222635343e0133321e0215140e01071e021514 +0e0123222e0135343633321e0115140623c330a25d77641532573f88121271485f2c5c5e4e8e2a0406042e3e3e2e2d406aa7 +543e8a70474d865059a0617cca7060c17b443321371f46319e4644cb813a74643c131210096c9b46627e3b3c0101402d2c40 +402c58824325456c4556926a1a11649c5a71b76749926633441f3820324400020073ffe905c505a4004800590056404d2301 +512b474202183d020933270a0c00082720510006150149011201272b181a063d2600090007040441012e2709450147016a0f +2e09052315025b274d01065b561c00066a38050006045b0f032b2b31002b2a3005222e01023534123e0133321e0112151402 +232226270e0123222e0135343e01333216173332161511141633323635342e0223220e0215141e0233323e01373332161514 +070401323637112e0223220e0215141616031d92f9ba6565baf99291fab9644c8948780f30894b76ba6a6aba76579a2f6706 +0a1e245e355ca3e98484e9a55d5ba8ea8461c3bc595c060b0dfec0fea5528a26194d673542643e2039741777d101098d8d01 +09d17676d1fef78dbcfef948413e4b7fd27270d37f624e0b07fde72a4bf29a80fbbf7071bdf88282f3c3701f3a2c0c070e04 +9601506b5201a23455334f788b3b54ba800000010073ffd305e105a4003f0044403a36300c0b090538030922012501382229 +0c0c08160103221909100702041309360a02073e090c012d01251602510f0719054a3e1d000602410f032b2b31003f2b2b30 +251e013332363d013421352115220615111406232226270e012322240235341236243332161737363b0132161511142b0122 +35342e012726232206070e01151001d74ad57472baff00024b414c0b0713591a32d675c7feb9be6ec50106936abd4a770c02 +0f060a1025132f4930739572d0474b3adb5a66746bac414848162bfe6c070b5a235654cd0157c5910112d0755b53a8060a07 +fdd712123b92833270665a60f58bfec60001004a0000057b057700220026401d19010922110c02080104130f000922120f01 +0412511e05000501240f032b2b3f2e2e2b3021353236351134262b0122070e010723132113232e0127262b01220e01151114 +163315015a67c2313756a94725200b3b2704e3273c0c1d2648a85625291ac26648172a04652c154a25a37b01d5fe2b849b24 +4a061d1efb9b2a17480000020052ffe903f203960032003e0047403e0b010904090926170a00081101240127043b14062c1f +0236262f091007030429096a252200053b012c015b1b0503060e0133011401570b00190603400f032b31003f2b2b30373436 +243335342e01232207321615140623222635343633321e01151114163332363d013315140e01232226270e01232226263714 +1633323e013d0122060652c0010d7934623b884727333a28293ac47653a86b222422213c30512f3c57052694544e9765a66a +48426c405dc380c97a993f543b6f473d3b27293a3a296c69478458fe332843442783832e53315d404d5b2e634f486242723f +d53d82000001003d0000044c038900280035402b0b010c0120270f0a0c08010418090a0a0009170119015b121d140528010a +01020b015b24051506022a0f032b31003f3f3f2b30333532363511342e01233525153e013332161511141633152135323635 +1134262322061511141633153d465a213e41012929a15f8e8f5a46fe2b465a3a5a77995a4548162b022f37310b4816c85870 +888cfe142b164848162b01e66481be79fe6c2b16480000010000020603fe023b000300174010270200000601043603010005 +01050f032b31002b301135211503fe020635350000010000020607fe023b000300174010270200000601042b030100050105 +0f032b31002b301135211507fe0206353500000100c7fe0002a8060000200016400f1f0d1b100212601705000501220f032b +2b2e2e30012e010a0135341a013637343b0132161514070e0202151001161514062b0122027b72a56934346ba66f0a13060a +0464855124015c060b05130afe045ae90108012091930120010ae857040b07090462e0fdfef193fd75feae060b050d000001 +0066ffd30398055400460043403b443e00030d0409201b022b01121d2911062c13020d272f0a040804233709000703042624 +02513307010541013b00021b1202682c17150602480f032b31002b2b30371e02333236353426272e0123220e020723222635 +1134363b01163332373332161d0114230e01232227113e0133321e0115140e0123222e01353436333216151406232226b215 +5777409470050b135f4545633e300617050f0d07068a9b988d06070c0446d3715256446b5371b36079d07a65a9613c2d2d3d +3d2d0712e93c6237e6a447612d486c2a383e020d0602ac050b42420a06130a5d6817fe7d372f82d16d7bd27c68b0632e3a3b +2d2c3d0300010035000002ae0577000f001a4013080c00090f0907010412510c04000501110f032b2b3f3f30333532351134 +2335211522151114331535dddd0279dddd4841046541484841fb9b41480000010027ffd305d70577001e002a402115011613 +07030422060c0a0801040d1d0914100d0c0907062f1605010501200f032b31003f2e2b3005012e012335211522151e011509 +01363534262335211522060701062b012202d1fe1d12664f0233aa010101890173045c3901ba4d7519fe31061b1a1b170505 +2b16484835030504fbeb03dd0811322e48483940fb33160000010044ffe903520396002a003040282824140e04161e091624 +080a00081e24000900070204280114014e0b111105551a040006022c0f032b31002b2b3005222e0135343e01333216151406 +232226353436372623220e0115141e0133323637343b0132161d01060601fe7cca7473cb7c78c5392929392e224780627830 +3b83636188191019060a1fb81781d77979de855e6b283b3b282435072d82c05e63b97977600c0b0706798e00000100ec044e +0312058d0005001840100504000313020c3f0301000501070f032b31003f2a300127090107270114280114011229e9044e2b +0114feec2bcd00020035fe73042d0389001d002d003e403408012a21090a010b012a250e0a0c081801212616091007020409 +0a000755122600051d011e010901020a015b19051d06022f0f032b31003f3f2b2b301335323635113426233525153e013332 +1e0115140e012322271114163315031e0133323e0235342e012322060735465a5050012f38955479c26d79d17d95675b45a0 +24804c476d4a233b7956538b29fe7347182a03db381c48167f3e4183d5777cd67f79fe9a2a18470254495f4c808d4252bf83 +554900010085028d0379060000370030402935302b281c19140f0c000a13250103013534332d2b2a22211918110f0e06050f +3a1f090b0501390f032b31002a301322263534372d012635343633321705032734363332161d010325363332161514070d01 +1615140623222725131514062322263537130506c117251d0127fed91d2418100e01041e02251816252001040e1019231dfe +d901271d2319110dfefc2025161825021efefc0c034c2718220f8c890f221a260bbe014c0417201e1904feb4be0b261a220f +898c0f2218270abefeb5041820211704014bbe0a00010073ffd303e1056800200024401d0e010c011701141207150601041e +09140c0603124e1b00000501220f032b2b3f2b3025343e023713232007060723133315141633211514060701060211140623 +22260164284d6d41bbeafe940b1b183b433cfa78017d0101fee668343a28293a3572dad5cd5a01040a219c01ae0625163502 +0202fe749afe88fee7283a3a0001003f000005e30577002a0041403a2625240c040601091401151209030622080c0a08291f +1c031e01012200090a0702042a221f1d1815130f0907010b122701510c040805012c0f032b2b2b2b30333532351134233521 +15221511013635342623352115220709011e013315213532363534270107111433153fd3d30265d302791a372301bda87ffe +9501c1375363fde831431afe91e5d34841046541484841fd6802601c1c2021484879fea4fd6751284848142519270220ddfe +854148000001002f000005cf057700310046403e2a2911100408010919011a170b0308220a0c0a0830242103230101220009 +0a070204312d2a2927241d1c1a181411100e0b09040312302201010501330f032b31002b2b303335323709012e0123352115 +220615141701133635342623352115220709011e0133152135323635342709010615141633152fd0530154fe87206d54023d +256002010cec08532e01f4d053fee701b1236b53fdc2216503febdfed906522d487401fa023e261548481d1a0404fe680160 +120b2a30484875fe5dfd6c271448481d1a060201eefe490c102a304800020039ffe903520396002000280033402b1e1c020f +14092626080a000828220f000614240009000703040d015c1e22080521015411041006022a0f032b31002b2b3005222e0135 +343e0133321e021514232115141633323e01373e013b01321506060121342e0123220601fe7dd1776dc3785e8b5a2e15fdaf +899b3f6b4f0e020b0712151dc0fe7901d32b6451747f1783db7a78d8853f70985b1b16aaf4386439070b1a749502234d9e69 +d90000010035000002e903890023002e40260b01150c021b270f0a0c0801040a0a00091a1812031223010a01020b015d2005 +150501250f032b2b3f3f2b30333532363511342e01233525153e0133321615140623222635343723220e0115111433153546 +5a213e410125217a573d6035272636270c53692cc748162b022f37310b4816c8596f483b25373626371778b251feb0414800 +0000060001000000000000000000055400560000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000023700ac040000560754004804e3 +00730237008f023700ac04000039031b0027023700ac023700ac023700ac05aa00460637007304000044000000000237003f +043700270000000006aa00730400005006370073061b0044063700730437003504370019040001020000000006aa00730400 +006603c700730537003f0000000003c70073000000000471007306aa003d038d0039023700ac040000390600003f0600003f +023700f20000000000000000047100350400003900000000031b007304000056041b004c083700250237002d047100440437 +0044040000aa06370073040000560500003f0600001702710042000000000327004402aa000002aa0017023700ac06000042 +0600003f0400012f0471003d0471003d000000000400007305c7007300000000057100440271ffa60000000005c700250400 +0073040000b20571003f00000000023700ac0000000005e300440237003f0437002700000000063700560400005606370073 +0646007305c7004a00000000040000520471003d0400000008000000031b00c70400006602e3003506000027038d00440400 +00ec0471003504000085040000730637003f0600002f038d0039000000000321003500010000008500600004000000000002 +000c00060016000000c40062000400010001000005a4fe4600000837ffa6ff8e081200010000000000000000000000000000 +0085000003e7019000050000019a01710000fe5a019a0171000004a2006602120000020b0500000000000000000000000000 +000000000000000000000000000000400020007e05a4fe5a000006000200000000>]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-0 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 5970 dict dup begin +/.notdef 0 def +/.null 1 def +/nonmarkingreturn 2 def +/space 3 def +/exclam 4 def +/quotedbl 5 def +/numbersign 6 def +/dollar 7 def +/percent 8 def +/ampersand 9 def +/quotesingle 10 def +/parenleft 11 def +/parenright 12 def +/asterisk 13 def +/plus 14 def +/comma 15 def +/hyphen 16 def +/period 17 def +/slash 18 def +/zero 19 def +/one 20 def +/two 21 def +/three 22 def +/four 23 def +/five 24 def +/six 25 def +/seven 26 def +/eight 27 def +/nine 28 def +/colon 29 def +/semicolon 30 def +/less 31 def +/equal 32 def +/greater 33 def +/question 34 def +/at 35 def +/A 36 def +/B 37 def +/C 38 def +/D 39 def +/E 40 def +/F 41 def +/G 42 def +/H 43 def +/I 44 def +/J 45 def +/K 46 def +/L 47 def +/M 48 def +/N 49 def +/O 50 def +/P 51 def +/Q 52 def +/R 53 def +/S 54 def +/T 55 def +/U 56 def +/V 57 def +/W 58 def +/X 59 def +/Y 60 def +/Z 61 def +/bracketleft 62 def +/backslash 63 def +/bracketright 64 def +/asciicircum 65 def +/underscore 66 def +/grave 67 def +/a 68 def +/b 69 def +/c 70 def +/d 71 def +/e 72 def +/f 73 def +/g 74 def +/h 75 def +/i 76 def +/j 77 def +/k 78 def +/l 79 def +/m 80 def +/n 81 def +/o 82 def +/p 83 def +/q 84 def +/r 85 def +/s 86 def +/t 87 def +/u 88 def +/v 89 def +/w 90 def +/x 91 def +/y 92 def +/z 93 def +/braceleft 94 def +/bar 95 def +/braceright 96 def +/asciitilde 97 def +/nonbreakingspace 98 def +/exclamdown 99 def +/cent 100 def +/sterling 101 def +/currency 102 def +/yen 103 def +/brokenbar 104 def +/section 105 def +/dieresis 106 def +/copyright 107 def +/ordfeminine 108 def +/guillemotleft 109 def +/logicalnot 110 def +/sfthyphen 111 def +/registered 112 def +/macron 113 def +/degree 114 def +/plusminus 115 def +/twosuperior 116 def +/threesuperior 117 def +/acute 118 def +/mu 119 def +/paragraph 120 def +/periodcentered 121 def +/cedilla 122 def +/onesuperior 123 def +/ordmasculine 124 def +/guillemotright 125 def +/onequarter 126 def +/onehalf 127 def +/threequarters 128 def +/questiondown 129 def +/Agrave 130 def +/Aacute 131 def +/Acircumflex 132 def +/Atilde 133 def +/Adieresis 134 def +/Aring 135 def +/AE 136 def +/Ccedilla 137 def +/Egrave 138 def +/Eacute 139 def +/Ecircumflex 140 def +/Edieresis 141 def +/Igrave 142 def +/Iacute 143 def +/Icircumflex 144 def +/Idieresis 145 def +/Eth 146 def +/Ntilde 147 def +/Ograve 148 def +/Oacute 149 def +/Ocircumflex 150 def +/Otilde 151 def +/Odieresis 152 def +/multiply 153 def +/Oslash 154 def +/Ugrave 155 def +/Uacute 156 def +/Ucircumflex 157 def +/Udieresis 158 def +/Yacute 159 def +/Thorn 160 def +/germandbls 161 def +/agrave 162 def +/aacute 163 def +/acircumflex 164 def +/atilde 165 def +/adieresis 166 def +/aring 167 def +/ae 168 def +/ccedilla 169 def +/egrave 170 def +/eacute 171 def +/ecircumflex 172 def +/edieresis 173 def +/igrave 174 def +/iacute 175 def +/icircumflex 176 def +/idieresis 177 def +/eth 178 def +/ntilde 179 def +/ograve 180 def +/oacute 181 def +/ocircumflex 182 def +/otilde 183 def +/odieresis 184 def +/divide 185 def +/oslash 186 def +/ugrave 187 def +/uacute 188 def +/ucircumflex 189 def +/udieresis 190 def +/yacute 191 def +/thorn 192 def +/ydieresis 193 def +/Amacron 194 def +/amacron 195 def +/Abreve 196 def +/abreve 197 def +/Aogonek 198 def +/aogonek 199 def +/Cacute 200 def +/cacute 201 def +/Ccircumflex 202 def +/ccircumflex 203 def +/Cdotaccent 204 def +/cdotaccent 205 def +/Ccaron 206 def +/ccaron 207 def +/Dcaron 208 def +/dcaron 209 def +/Dcroat 210 def +/dcroat 211 def +/Emacron 212 def +/emacron 213 def +/Ebreve 214 def +/ebreve 215 def +/Edotaccent 216 def +/edotaccent 217 def +/Eogonek 218 def +/eogonek 219 def +/Ecaron 220 def +/ecaron 221 def +/Gcircumflex 222 def +/gcircumflex 223 def +/Gbreve 224 def +/gbreve 225 def +/Gdotaccent 226 def +/gdotaccent 227 def +/Gcommaaccent 228 def +/gcommaaccent 229 def +/Hcircumflex 230 def +/hcircumflex 231 def +/Hbar 232 def +/hbar 233 def +/Itilde 234 def +/itilde 235 def +/Imacron 236 def +/imacron 237 def +/Ibreve 238 def +/ibreve 239 def +/Iogonek 240 def +/iogonek 241 def +/Idotaccent 242 def +/dotlessi 243 def +/IJ 244 def +/ij 245 def +/Jcircumflex 246 def +/jcircumflex 247 def +/Kcommaaccent 248 def +/kcommaaccent 249 def +/kgreenlandic 250 def +/Lacute 251 def +/lacute 252 def +/Lcommaaccent 253 def +/lcommaaccent 254 def +/Lcaron 255 def +/lcaron 256 def +/Ldot 257 def +/ldot 258 def +/Lslash 259 def +/lslash 260 def +/Nacute 261 def +/nacute 262 def +/Ncommaaccent 263 def +/ncommaaccent 264 def +/Ncaron 265 def +/ncaron 266 def +/napostrophe 267 def +/Eng 268 def +/eng 269 def +/Omacron 270 def +/omacron 271 def +/Obreve 272 def +/obreve 273 def +/Ohungarumlaut 274 def +/ohungarumlaut 275 def +/OE 276 def +/oe 277 def +/Racute 278 def +/racute 279 def +/Rcommaaccent 280 def +/rcommaaccent 281 def +/Rcaron 282 def +/rcaron 283 def +/Sacute 284 def +/sacute 285 def +/Scircumflex 286 def +/scircumflex 287 def +/Scedilla 288 def +/scedilla 289 def +/Scaron 290 def +/scaron 291 def +/Tcommaaccent 292 def +/tcommaaccent 293 def +/Tcaron 294 def +/tcaron 295 def +/Tbar 296 def +/tbar 297 def +/Utilde 298 def +/utilde 299 def +/Umacron 300 def +/umacron 301 def +/Ubreve 302 def +/ubreve 303 def +/Uring 304 def +/uring 305 def +/Uhungarumlaut 306 def +/uhungarumlaut 307 def +/Uogonek 308 def +/uogonek 309 def +/Wcircumflex 310 def +/wcircumflex 311 def +/Ycircumflex 312 def +/ycircumflex 313 def +/Ydieresis 314 def +/Zacute 315 def +/zacute 316 def +/Zdotaccent 317 def +/zdotaccent 318 def +/Zcaron 319 def +/zcaron 320 def +/longs 321 def +/uni0180 322 def +/uni0181 323 def +/uni0182 324 def +/uni0183 325 def +/uni0184 326 def +/uni0185 327 def +/uni0186 328 def +/uni0187 329 def +/uni0188 330 def +/uni0189 331 def +/uni018A 332 def +/uni018B 333 def +/uni018C 334 def +/uni018D 335 def +/uni018E 336 def +/uni018F 337 def +/uni0190 338 def +/uni0191 339 def +/florin 340 def +/uni0193 341 def +/uni0194 342 def +/uni0195 343 def +/uni0196 344 def +/uni0197 345 def +/uni0198 346 def +/uni0199 347 def +/uni019A 348 def +/uni019B 349 def +/uni019C 350 def +/uni019D 351 def +/uni019E 352 def +/uni019F 353 def +/Ohorn 354 def +/ohorn 355 def +/uni01A2 356 def +/uni01A3 357 def +/uni01A4 358 def +/uni01A5 359 def +/uni01A6 360 def +/uni01A7 361 def +/uni01A8 362 def +/uni01A9 363 def +/uni01AA 364 def +/uni01AB 365 def +/uni01AC 366 def +/uni01AD 367 def +/uni01AE 368 def +/Uhorn 369 def +/uhorn 370 def +/uni01B1 371 def +/uni01B2 372 def +/uni01B3 373 def +/uni01B4 374 def +/uni01B5 375 def +/uni01B6 376 def +/uni01B7 377 def +/uni01B8 378 def +/uni01B9 379 def +/uni01BA 380 def +/uni01BB 381 def +/uni01BC 382 def +/uni01BD 383 def +/uni01BE 384 def +/uni01BF 385 def +/uni01C0 386 def +/uni01C1 387 def +/uni01C2 388 def +/uni01C3 389 def +/uni01C4 390 def +/uni01C5 391 def +/uni01C6 392 def +/uni01C7 393 def +/uni01C8 394 def +/uni01C9 395 def +/uni01CA 396 def +/uni01CB 397 def +/uni01CC 398 def +/uni01CD 399 def +/uni01CE 400 def +/uni01CF 401 def +/uni01D0 402 def +/uni01D1 403 def +/uni01D2 404 def +/uni01D3 405 def +/uni01D4 406 def +/uni01D5 407 def +/uni01D6 408 def +/uni01D7 409 def +/uni01D8 410 def +/uni01D9 411 def +/uni01DA 412 def +/uni01DB 413 def +/uni01DC 414 def +/uni01DD 415 def +/uni01DE 416 def +/uni01DF 417 def +/uni01E0 418 def +/uni01E1 419 def +/uni01E2 420 def +/uni01E3 421 def +/uni01E4 422 def +/uni01E5 423 def +/Gcaron 424 def +/gcaron 425 def +/uni01E8 426 def +/uni01E9 427 def +/uni01EA 428 def +/uni01EB 429 def +/uni01EC 430 def +/uni01ED 431 def +/uni01EE 432 def +/uni01EF 433 def +/uni01F0 434 def +/uni01F1 435 def +/uni01F2 436 def +/uni01F3 437 def +/uni01F4 438 def +/uni01F5 439 def +/uni01F6 440 def +/uni01F7 441 def +/uni01F8 442 def +/uni01F9 443 def +/Aringacute 444 def +/aringacute 445 def +/AEacute 446 def +/aeacute 447 def +/Oslashacute 448 def +/oslashacute 449 def +/uni0200 450 def +/uni0201 451 def +/uni0202 452 def +/uni0203 453 def +/uni0204 454 def +/uni0205 455 def +/uni0206 456 def +/uni0207 457 def +/uni0208 458 def +/uni0209 459 def +/uni020A 460 def +/uni020B 461 def +/uni020C 462 def +/uni020D 463 def +/uni020E 464 def +/uni020F 465 def +/uni0210 466 def +/uni0211 467 def +/uni0212 468 def +/uni0213 469 def +/uni0214 470 def +/uni0215 471 def +/uni0216 472 def +/uni0217 473 def +/Scommaaccent 474 def +/scommaaccent 475 def +/uni021A 476 def +/uni021B 477 def +/uni021C 478 def +/uni021D 479 def +/uni021E 480 def +/uni021F 481 def +/uni0220 482 def +/uni0221 483 def +/uni0222 484 def +/uni0223 485 def +/uni0224 486 def +/uni0225 487 def +/uni0226 488 def +/uni0227 489 def +/uni0228 490 def +/uni0229 491 def +/uni022A 492 def +/uni022B 493 def +/uni022C 494 def +/uni022D 495 def +/uni022E 496 def +/uni022F 497 def +/uni0230 498 def +/uni0231 499 def +/uni0232 500 def +/uni0233 501 def +/uni0234 502 def +/uni0235 503 def +/uni0236 504 def +/dotlessj 505 def +/uni0238 506 def +/uni0239 507 def +/uni023A 508 def +/uni023B 509 def +/uni023C 510 def +/uni023D 511 def +/uni023E 512 def +/uni023F 513 def +/uni0240 514 def +/uni0241 515 def +/uni0242 516 def +/uni0243 517 def +/uni0244 518 def +/uni0245 519 def +/uni0246 520 def +/uni0247 521 def +/uni0248 522 def +/uni0249 523 def +/uni024A 524 def +/uni024B 525 def +/uni024C 526 def +/uni024D 527 def +/uni024E 528 def +/uni024F 529 def +/uni0250 530 def +/uni0251 531 def +/uni0252 532 def +/uni0253 533 def +/uni0254 534 def +/uni0255 535 def +/uni0256 536 def +/uni0257 537 def +/uni0258 538 def +/uni0259 539 def +/uni025A 540 def +/uni025B 541 def +/uni025C 542 def +/uni025D 543 def +/uni025E 544 def +/uni025F 545 def +/uni0260 546 def +/uni0261 547 def +/uni0262 548 def +/uni0263 549 def +/uni0264 550 def +/uni0265 551 def +/uni0266 552 def +/uni0267 553 def +/uni0268 554 def +/uni0269 555 def +/uni026A 556 def +/uni026B 557 def +/uni026C 558 def +/uni026D 559 def +/uni026E 560 def +/uni026F 561 def +/uni0270 562 def +/uni0271 563 def +/uni0272 564 def +/uni0273 565 def +/uni0274 566 def +/uni0275 567 def +/uni0276 568 def +/uni0277 569 def +/uni0278 570 def +/uni0279 571 def +/uni027A 572 def +/uni027B 573 def +/uni027C 574 def +/uni027D 575 def +/uni027E 576 def +/uni027F 577 def +/uni0280 578 def +/uni0281 579 def +/uni0282 580 def +/uni0283 581 def +/uni0284 582 def +/uni0285 583 def +/uni0286 584 def +/uni0287 585 def +/uni0288 586 def +/uni0289 587 def +/uni028A 588 def +/uni028B 589 def +/uni028C 590 def +/uni028D 591 def +/uni028E 592 def +/uni028F 593 def +/uni0290 594 def +/uni0291 595 def +/uni0292 596 def +/uni0293 597 def +/uni0294 598 def +/uni0295 599 def +/uni0296 600 def +/uni0297 601 def +/uni0298 602 def +/uni0299 603 def +/uni029A 604 def +/uni029B 605 def +/uni029C 606 def +/uni029D 607 def +/uni029E 608 def +/uni029F 609 def +/uni02A0 610 def +/uni02A1 611 def +/uni02A2 612 def +/uni02A3 613 def +/uni02A4 614 def +/uni02A5 615 def +/uni02A6 616 def +/uni02A7 617 def +/uni02A8 618 def +/uni02A9 619 def +/uni02AA 620 def +/uni02AB 621 def +/uni02AC 622 def +/uni02AD 623 def +/uni02AE 624 def +/uni02AF 625 def +/uni02B0 626 def +/uni02B1 627 def +/uni02B2 628 def +/uni02B3 629 def +/uni02B4 630 def +/uni02B5 631 def +/uni02B6 632 def +/uni02B7 633 def +/uni02B8 634 def +/uni02B9 635 def +/uni02BA 636 def +/uni02BB 637 def +/uni02BC 638 def +/uni02BD 639 def +/uni02BE 640 def +/uni02BF 641 def +/uni02C0 642 def +/uni02C1 643 def +/uni02C2 644 def +/uni02C3 645 def +/uni02C4 646 def +/uni02C5 647 def +/circumflex 648 def +/caron 649 def +/uni02C8 650 def +/uni02C9 651 def +/uni02CA 652 def +/uni02CB 653 def +/uni02CC 654 def +/uni02CD 655 def +/uni02CE 656 def +/uni02CF 657 def +/uni02D0 658 def +/uni02D1 659 def +/uni02D2 660 def +/uni02D3 661 def +/uni02D4 662 def +/uni02D5 663 def +/uni02D6 664 def +/uni02D7 665 def +/breve 666 def +/dotaccent 667 def +/ring 668 def +/ogonek 669 def +/tilde 670 def +/hungarumlaut 671 def +/uni02DE 672 def +/uni02DF 673 def +/uni02E0 674 def +/uni02E1 675 def +/uni02E2 676 def +/uni02E3 677 def +/uni02E4 678 def +/uni02E5 679 def +/uni02E6 680 def +/uni02E7 681 def +/uni02E8 682 def +/uni02E9 683 def +/uni02EC 684 def +/uni02ED 685 def +/uni02EE 686 def +/uni02F3 687 def +/uni02F7 688 def +/gravecomb 689 def +/acutecomb 690 def +/uni0302 691 def +/tildecomb 692 def +/uni0304 693 def +/uni0305 694 def +/uni0306 695 def +/uni0307 696 def +/uni0308 697 def +/hookabovecomb 698 def +/uni030A 699 def +/uni030B 700 def +/uni030C 701 def +/uni030D 702 def +/uni030E 703 def +/uni030F 704 def +/uni0310 705 def +/uni0311 706 def +/uni0312 707 def +/uni0313 708 def +/uni0314 709 def +/uni0315 710 def +/uni0316 711 def +/uni0317 712 def +/uni0318 713 def +/uni0319 714 def +/uni031A 715 def +/uni031B 716 def +/uni031C 717 def +/uni031D 718 def +/uni031E 719 def +/uni031F 720 def +/uni0320 721 def +/uni0321 722 def +/uni0322 723 def +/dotbelowcomb 724 def +/uni0324 725 def +/uni0325 726 def +/uni0326 727 def +/uni0327 728 def +/uni0328 729 def +/uni0329 730 def +/uni032A 731 def +/uni032B 732 def +/uni032C 733 def +/uni032D 734 def +/uni032E 735 def +/uni032F 736 def +/uni0330 737 def +/uni0331 738 def +/uni0332 739 def +/uni0333 740 def +/uni0334 741 def +/uni0335 742 def +/uni0336 743 def +/uni0337 744 def +/uni0338 745 def +/uni0339 746 def +/uni033A 747 def +/uni033B 748 def +/uni033C 749 def +/uni033D 750 def +/uni033E 751 def +/uni033F 752 def +/uni0340 753 def +/uni0341 754 def +/uni0342 755 def +/uni0343 756 def +/uni0344 757 def +/uni0345 758 def +/uni0346 759 def +/uni0347 760 def +/uni0348 761 def +/uni0349 762 def +/uni034A 763 def +/uni034B 764 def +/uni034C 765 def +/uni034D 766 def +/uni034E 767 def +/uni034F 768 def +/uni0351 769 def +/uni0352 770 def +/uni0353 771 def +/uni0357 772 def +/uni0358 773 def +/uni035A 774 def +/uni035C 775 def +/uni035D 776 def +/uni035E 777 def +/uni035F 778 def +/uni0360 779 def +/uni0361 780 def +/uni0362 781 def +/uni0370 782 def +/uni0371 783 def +/uni0372 784 def +/uni0373 785 def +/uni0374 786 def +/uni0375 787 def +/uni0376 788 def +/uni0377 789 def +/uni037A 790 def +/uni037B 791 def +/uni037C 792 def +/uni037D 793 def +/uni037E 794 def +/tonos 795 def +/dieresistonos 796 def +/Alphatonos 797 def +/anoteleia 798 def +/Epsilontonos 799 def +/Etatonos 800 def +/Iotatonos 801 def +/Omicrontonos 802 def +/Upsilontonos 803 def +/Omegatonos 804 def +/iotadieresistonos 805 def +/Alpha 806 def +/Beta 807 def +/Gamma 808 def +/uni0394 809 def +/Epsilon 810 def +/Zeta 811 def +/Eta 812 def +/Theta 813 def +/Iota 814 def +/Kappa 815 def +/Lambda 816 def +/Mu 817 def +/Nu 818 def +/Xi 819 def +/Omicron 820 def +/Pi 821 def +/Rho 822 def +/Sigma 823 def +/Tau 824 def +/Upsilon 825 def +/Phi 826 def +/Chi 827 def +/Psi 828 def +/Omega 829 def +/Iotadieresis 830 def +/Upsilondieresis 831 def +/alphatonos 832 def +/epsilontonos 833 def +/etatonos 834 def +/iotatonos 835 def +/upsilondieresistonos 836 def +/alpha 837 def +/beta 838 def +/gamma 839 def +/delta 840 def +/epsilon 841 def +/zeta 842 def +/eta 843 def +/theta 844 def +/iota 845 def +/kappa 846 def +/lambda 847 def +/uni03BC 848 def +/nu 849 def +/xi 850 def +/omicron 851 def +/pi 852 def +/rho 853 def +/sigma1 854 def +/sigma 855 def +/tau 856 def +/upsilon 857 def +/phi 858 def +/chi 859 def +/psi 860 def +/omega 861 def +/iotadieresis 862 def +/upsilondieresis 863 def +/omicrontonos 864 def +/upsilontonos 865 def +/omegatonos 866 def +/uni03CF 867 def +/uni03D0 868 def +/theta1 869 def +/Upsilon1 870 def +/uni03D3 871 def +/uni03D4 872 def +/phi1 873 def +/omega1 874 def +/uni03D7 875 def +/uni03D8 876 def +/uni03D9 877 def +/uni03DA 878 def +/uni03DB 879 def +/uni03DC 880 def +/uni03DD 881 def +/uni03DE 882 def +/uni03DF 883 def +/uni03E0 884 def +/uni03E1 885 def +/uni03E2 886 def +/uni03E3 887 def +/uni03E4 888 def +/uni03E5 889 def +/uni03E6 890 def +/uni03E7 891 def +/uni03E8 892 def +/uni03E9 893 def +/uni03EA 894 def +/uni03EB 895 def +/uni03EC 896 def +/uni03ED 897 def +/uni03EE 898 def +/uni03EF 899 def +/uni03F0 900 def +/uni03F1 901 def +/uni03F2 902 def +/uni03F3 903 def +/uni03F4 904 def +/uni03F5 905 def +/uni03F6 906 def +/uni03F7 907 def +/uni03F8 908 def +/uni03F9 909 def +/uni03FA 910 def +/uni03FB 911 def +/uni03FC 912 def +/uni03FD 913 def +/uni03FE 914 def +/uni03FF 915 def +/uni0400 916 def +/uni0401 917 def +/uni0402 918 def +/uni0403 919 def +/uni0404 920 def +/uni0405 921 def +/uni0406 922 def +/uni0407 923 def +/uni0408 924 def +/uni0409 925 def +/uni040A 926 def +/uni040B 927 def +/uni040C 928 def +/uni040D 929 def +/uni040E 930 def +/uni040F 931 def +/uni0410 932 def +/uni0411 933 def +/uni0412 934 def +/uni0413 935 def +/uni0414 936 def +/uni0415 937 def +/uni0416 938 def +/uni0417 939 def +/uni0418 940 def +/uni0419 941 def +/uni041A 942 def +/uni041B 943 def +/uni041C 944 def +/uni041D 945 def +/uni041E 946 def +/uni041F 947 def +/uni0420 948 def +/uni0421 949 def +/uni0422 950 def +/uni0423 951 def +/uni0424 952 def +/uni0425 953 def +/uni0426 954 def +/uni0427 955 def +/uni0428 956 def +/uni0429 957 def +/uni042A 958 def +/uni042B 959 def +/uni042C 960 def +/uni042D 961 def +/uni042E 962 def +/uni042F 963 def +/uni0430 964 def +/uni0431 965 def +/uni0432 966 def +/uni0433 967 def +/uni0434 968 def +/uni0435 969 def +/uni0436 970 def +/uni0437 971 def +/uni0438 972 def +/uni0439 973 def +/uni043A 974 def +/uni043B 975 def +/uni043C 976 def +/uni043D 977 def +/uni043E 978 def +/uni043F 979 def +/uni0440 980 def +/uni0441 981 def +/uni0442 982 def +/uni0443 983 def +/uni0444 984 def +/uni0445 985 def +/uni0446 986 def +/uni0447 987 def +/uni0448 988 def +/uni0449 989 def +/uni044A 990 def +/uni044B 991 def +/uni044C 992 def +/uni044D 993 def +/uni044E 994 def +/uni044F 995 def +/uni0450 996 def +/uni0451 997 def +/uni0452 998 def +/uni0453 999 def +/uni0454 1000 def +/uni0455 1001 def +/uni0456 1002 def +/uni0457 1003 def +/uni0458 1004 def +/uni0459 1005 def +/uni045A 1006 def +/uni045B 1007 def +/uni045C 1008 def +/uni045D 1009 def +/uni045E 1010 def +/uni045F 1011 def +/uni0460 1012 def +/uni0461 1013 def +/uni0462 1014 def +/uni0463 1015 def +/uni0464 1016 def +/uni0465 1017 def +/uni0466 1018 def +/uni0467 1019 def +/uni0468 1020 def +/uni0469 1021 def +/uni046A 1022 def +/uni046B 1023 def +/uni046C 1024 def +/uni046D 1025 def +/uni046E 1026 def +/uni046F 1027 def +/uni0470 1028 def +/uni0471 1029 def +/uni0472 1030 def +/uni0473 1031 def +/uni0474 1032 def +/uni0475 1033 def +/uni0476 1034 def +/uni0477 1035 def +/uni0478 1036 def +/uni0479 1037 def +/uni047A 1038 def +/uni047B 1039 def +/uni047C 1040 def +/uni047D 1041 def +/uni047E 1042 def +/uni047F 1043 def +/uni0480 1044 def +/uni0481 1045 def +/uni0482 1046 def +/uni0483 1047 def +/uni0484 1048 def +/uni0485 1049 def +/uni0486 1050 def +/uni0487 1051 def +/uni0488 1052 def +/uni0489 1053 def +/uni048A 1054 def +/uni048B 1055 def +/uni048C 1056 def +/uni048D 1057 def +/uni048E 1058 def +/uni048F 1059 def +/uni0490 1060 def +/uni0491 1061 def +/uni0492 1062 def +/uni0493 1063 def +/uni0494 1064 def +/uni0495 1065 def +/uni0496 1066 def +/uni0497 1067 def +/uni0498 1068 def +/uni0499 1069 def +/uni049A 1070 def +/uni049B 1071 def +/uni049C 1072 def +/uni049D 1073 def +/uni049E 1074 def +/uni049F 1075 def +/uni04A0 1076 def +/uni04A1 1077 def +/uni04A2 1078 def +/uni04A3 1079 def +/uni04A4 1080 def +/uni04A5 1081 def +/uni04A6 1082 def +/uni04A7 1083 def +/uni04A8 1084 def +/uni04A9 1085 def +/uni04AA 1086 def +/uni04AB 1087 def +/uni04AC 1088 def +/uni04AD 1089 def +/uni04AE 1090 def +/uni04AF 1091 def +/uni04B0 1092 def +/uni04B1 1093 def +/uni04B2 1094 def +/uni04B3 1095 def +/uni04B4 1096 def +/uni04B5 1097 def +/uni04B6 1098 def +/uni04B7 1099 def +/uni04B8 1100 def +/uni04B9 1101 def +/uni04BA 1102 def +/uni04BB 1103 def +/uni04BC 1104 def +/uni04BD 1105 def +/uni04BE 1106 def +/uni04BF 1107 def +/uni04C0 1108 def +/uni04C1 1109 def +/uni04C2 1110 def +/uni04C3 1111 def +/uni04C4 1112 def +/uni04C5 1113 def +/uni04C6 1114 def +/uni04C7 1115 def +/uni04C8 1116 def +/uni04C9 1117 def +/uni04CA 1118 def +/uni04CB 1119 def +/uni04CC 1120 def +/uni04CD 1121 def +/uni04CE 1122 def +/uni04CF 1123 def +/uni04D0 1124 def +/uni04D1 1125 def +/uni04D2 1126 def +/uni04D3 1127 def +/uni04D4 1128 def +/uni04D5 1129 def +/uni04D6 1130 def +/uni04D7 1131 def +/uni04D8 1132 def +/uni04D9 1133 def +/uni04DA 1134 def +/uni04DB 1135 def +/uni04DC 1136 def +/uni04DD 1137 def +/uni04DE 1138 def +/uni04DF 1139 def +/uni04E0 1140 def +/uni04E1 1141 def +/uni04E2 1142 def +/uni04E3 1143 def +/uni04E4 1144 def +/uni04E5 1145 def +/uni04E6 1146 def +/uni04E7 1147 def +/uni04E8 1148 def +/uni04E9 1149 def +/uni04EA 1150 def +/uni04EB 1151 def +/uni04EC 1152 def +/uni04ED 1153 def +/uni04EE 1154 def +/uni04EF 1155 def +/uni04F0 1156 def +/uni04F1 1157 def +/uni04F2 1158 def +/uni04F3 1159 def +/uni04F4 1160 def +/uni04F5 1161 def +/uni04F6 1162 def +/uni04F7 1163 def +/uni04F8 1164 def +/uni04F9 1165 def +/uni04FA 1166 def +/uni04FB 1167 def +/uni04FC 1168 def +/uni04FD 1169 def +/uni04FE 1170 def +/uni04FF 1171 def +/uni0500 1172 def +/uni0501 1173 def +/uni0502 1174 def +/uni0503 1175 def +/uni0504 1176 def +/uni0505 1177 def +/uni0506 1178 def +/uni0507 1179 def +/uni0508 1180 def +/uni0509 1181 def +/uni050A 1182 def +/uni050B 1183 def +/uni050C 1184 def +/uni050D 1185 def +/uni050E 1186 def +/uni050F 1187 def +/uni0510 1188 def +/uni0511 1189 def +/uni0512 1190 def +/uni0513 1191 def +/uni0514 1192 def +/uni0515 1193 def +/uni0516 1194 def +/uni0517 1195 def +/uni0518 1196 def +/uni0519 1197 def +/uni051A 1198 def +/uni051B 1199 def +/uni051C 1200 def +/uni051D 1201 def +/uni051E 1202 def +/uni051F 1203 def +/uni0520 1204 def +/uni0521 1205 def +/uni0522 1206 def +/uni0523 1207 def +/uni0524 1208 def +/uni0525 1209 def +/uni0531 1210 def +/uni0532 1211 def +/uni0533 1212 def +/uni0534 1213 def +/uni0535 1214 def +/uni0536 1215 def +/uni0537 1216 def +/uni0538 1217 def +/uni0539 1218 def +/uni053A 1219 def +/uni053B 1220 def +/uni053C 1221 def +/uni053D 1222 def +/uni053E 1223 def +/uni053F 1224 def +/uni0540 1225 def +/uni0541 1226 def +/uni0542 1227 def +/uni0543 1228 def +/uni0544 1229 def +/uni0545 1230 def +/uni0546 1231 def +/uni0547 1232 def +/uni0548 1233 def +/uni0549 1234 def +/uni054A 1235 def +/uni054B 1236 def +/uni054C 1237 def +/uni054D 1238 def +/uni054E 1239 def +/uni054F 1240 def +/uni0550 1241 def +/uni0551 1242 def +/uni0552 1243 def +/uni0553 1244 def +/uni0554 1245 def +/uni0555 1246 def +/uni0556 1247 def +/uni0559 1248 def +/uni055A 1249 def +/uni055B 1250 def +/uni055C 1251 def +/uni055D 1252 def +/uni055E 1253 def +/uni055F 1254 def +/uni0561 1255 def +/uni0562 1256 def +/uni0563 1257 def +/uni0564 1258 def +/uni0565 1259 def +/uni0566 1260 def +/uni0567 1261 def +/uni0568 1262 def +/uni0569 1263 def +/uni056A 1264 def +/uni056B 1265 def +/uni056C 1266 def +/uni056D 1267 def +/uni056E 1268 def +/uni056F 1269 def +/uni0570 1270 def +/uni0571 1271 def +/uni0572 1272 def +/uni0573 1273 def +/uni0574 1274 def +/uni0575 1275 def +/uni0576 1276 def +/uni0577 1277 def +/uni0578 1278 def +/uni0579 1279 def +/uni057A 1280 def +/uni057B 1281 def +/uni057C 1282 def +/uni057D 1283 def +/uni057E 1284 def +/uni057F 1285 def +/uni0580 1286 def +/uni0581 1287 def +/uni0582 1288 def +/uni0583 1289 def +/uni0584 1290 def +/uni0585 1291 def +/uni0586 1292 def +/uni0587 1293 def +/uni0589 1294 def +/uni058A 1295 def +/uni05B0 1296 def +/uni05B1 1297 def +/uni05B2 1298 def +/uni05B3 1299 def +/uni05B4 1300 def +/uni05B5 1301 def +/uni05B6 1302 def +/uni05B7 1303 def +/uni05B8 1304 def +/uni05B9 1305 def +/uni05BA 1306 def +/uni05BB 1307 def +/uni05BC 1308 def +/uni05BD 1309 def +/uni05BE 1310 def +/uni05BF 1311 def +/uni05C0 1312 def +/uni05C1 1313 def +/uni05C2 1314 def +/uni05C3 1315 def +/uni05C6 1316 def +/uni05C7 1317 def +/uni05D0 1318 def +/uni05D1 1319 def +/uni05D2 1320 def +/uni05D3 1321 def +/uni05D4 1322 def +/uni05D5 1323 def +/uni05D6 1324 def +/uni05D7 1325 def +/uni05D8 1326 def +/uni05D9 1327 def +/uni05DA 1328 def +/uni05DB 1329 def +/uni05DC 1330 def +/uni05DD 1331 def +/uni05DE 1332 def +/uni05DF 1333 def +/uni05E0 1334 def +/uni05E1 1335 def +/uni05E2 1336 def +/uni05E3 1337 def +/uni05E4 1338 def +/uni05E5 1339 def +/uni05E6 1340 def +/uni05E7 1341 def +/uni05E8 1342 def +/uni05E9 1343 def +/uni05EA 1344 def +/uni05F0 1345 def +/uni05F1 1346 def +/uni05F2 1347 def +/uni05F3 1348 def +/uni05F4 1349 def +/uni0606 1350 def +/uni0607 1351 def +/uni0609 1352 def +/uni060A 1353 def +/uni060C 1354 def +/uni0615 1355 def +/uni061B 1356 def +/uni061F 1357 def +/uni0621 1358 def +/uni0622 1359 def +/uni0623 1360 def +/uni0624 1361 def +/uni0625 1362 def +/uni0626 1363 def +/uni0627 1364 def +/uni0628 1365 def +/uni0629 1366 def +/uni062A 1367 def +/uni062B 1368 def +/uni062C 1369 def +/uni062D 1370 def +/uni062E 1371 def +/uni062F 1372 def +/uni0630 1373 def +/uni0631 1374 def +/uni0632 1375 def +/uni0633 1376 def +/uni0634 1377 def +/uni0635 1378 def +/uni0636 1379 def +/uni0637 1380 def +/uni0638 1381 def +/uni0639 1382 def +/uni063A 1383 def +/uni0640 1384 def +/uni0641 1385 def +/uni0642 1386 def +/uni0643 1387 def +/uni0644 1388 def +/uni0645 1389 def +/uni0646 1390 def +/uni0647 1391 def +/uni0648 1392 def +/uni0649 1393 def +/uni064A 1394 def +/uni064B 1395 def +/uni064C 1396 def +/uni064D 1397 def +/uni064E 1398 def +/uni064F 1399 def +/uni0650 1400 def +/uni0651 1401 def +/uni0652 1402 def +/uni0653 1403 def +/uni0654 1404 def +/uni0655 1405 def +/uni0657 1406 def +/uni065A 1407 def +/uni0660 1408 def +/uni0661 1409 def +/uni0662 1410 def +/uni0663 1411 def +/uni0664 1412 def +/uni0665 1413 def +/uni0666 1414 def +/uni0667 1415 def +/uni0668 1416 def +/uni0669 1417 def +/uni066A 1418 def +/uni066B 1419 def +/uni066C 1420 def +/uni066D 1421 def +/uni066E 1422 def +/uni066F 1423 def +/uni0670 1424 def +/uni0674 1425 def +/uni0679 1426 def +/uni067A 1427 def +/uni067B 1428 def +/uni067C 1429 def +/uni067D 1430 def +/uni067E 1431 def +/uni067F 1432 def +/uni0680 1433 def +/uni0681 1434 def +/uni0682 1435 def +/uni0683 1436 def +/uni0684 1437 def +/uni0685 1438 def +/uni0686 1439 def +/uni0687 1440 def +/uni0688 1441 def +/uni0689 1442 def +/uni068A 1443 def +/uni068B 1444 def +/uni068C 1445 def +/uni068D 1446 def +/uni068E 1447 def +/uni068F 1448 def +/uni0690 1449 def +/uni0691 1450 def +/uni0692 1451 def +/uni0693 1452 def +/uni0694 1453 def +/uni0695 1454 def +/uni0696 1455 def +/uni0697 1456 def +/uni0698 1457 def +/uni0699 1458 def +/uni069A 1459 def +/uni069B 1460 def +/uni069C 1461 def +/uni069D 1462 def +/uni069E 1463 def +/uni069F 1464 def +/uni06A0 1465 def +/uni06A1 1466 def +/uni06A2 1467 def +/uni06A3 1468 def +/uni06A4 1469 def +/uni06A5 1470 def +/uni06A6 1471 def +/uni06A7 1472 def +/uni06A8 1473 def +/uni06A9 1474 def +/uni06AA 1475 def +/uni06AB 1476 def +/uni06AC 1477 def +/uni06AD 1478 def +/uni06AE 1479 def +/uni06AF 1480 def +/uni06B0 1481 def +/uni06B1 1482 def +/uni06B2 1483 def +/uni06B3 1484 def +/uni06B4 1485 def +/uni06B5 1486 def +/uni06B6 1487 def +/uni06B7 1488 def +/uni06B8 1489 def +/uni06B9 1490 def +/uni06BA 1491 def +/uni06BB 1492 def +/uni06BC 1493 def +/uni06BD 1494 def +/uni06BE 1495 def +/uni06BF 1496 def +/uni06C6 1497 def +/uni06C7 1498 def +/uni06C8 1499 def +/uni06CB 1500 def +/uni06CC 1501 def +/uni06CE 1502 def +/uni06D0 1503 def +/uni06D5 1504 def +/uni06F0 1505 def +/uni06F1 1506 def +/uni06F2 1507 def +/uni06F3 1508 def +/uni06F4 1509 def +/uni06F5 1510 def +/uni06F6 1511 def +/uni06F7 1512 def +/uni06F8 1513 def +/uni06F9 1514 def +/uni07C0 1515 def +/uni07C1 1516 def +/uni07C2 1517 def +/uni07C3 1518 def +/uni07C4 1519 def +/uni07C5 1520 def +/uni07C6 1521 def +/uni07C7 1522 def +/uni07C8 1523 def +/uni07C9 1524 def +/uni07CA 1525 def +/uni07CB 1526 def +/uni07CC 1527 def +/uni07CD 1528 def +/uni07CE 1529 def +/uni07CF 1530 def +/uni07D0 1531 def +/uni07D1 1532 def +/uni07D2 1533 def +/uni07D3 1534 def +/uni07D4 1535 def +/uni07D5 1536 def +/uni07D6 1537 def +/uni07D7 1538 def +/uni07D8 1539 def +/uni07D9 1540 def +/uni07DA 1541 def +/uni07DB 1542 def +/uni07DC 1543 def +/uni07DD 1544 def +/uni07DE 1545 def +/uni07DF 1546 def +/uni07E0 1547 def +/uni07E1 1548 def +/uni07E2 1549 def +/uni07E3 1550 def +/uni07E4 1551 def +/uni07E5 1552 def +/uni07E6 1553 def +/uni07E7 1554 def +/uni07EB 1555 def +/uni07EC 1556 def +/uni07ED 1557 def +/uni07EE 1558 def +/uni07EF 1559 def +/uni07F0 1560 def +/uni07F1 1561 def +/uni07F2 1562 def +/uni07F3 1563 def +/uni07F4 1564 def +/uni07F5 1565 def +/uni07F8 1566 def +/uni07F9 1567 def +/uni07FA 1568 def +/uni0E3F 1569 def +/uni0E81 1570 def +/uni0E82 1571 def +/uni0E84 1572 def +/uni0E87 1573 def +/uni0E88 1574 def +/uni0E8A 1575 def +/uni0E8D 1576 def +/uni0E94 1577 def +/uni0E95 1578 def +/uni0E96 1579 def +/uni0E97 1580 def +/uni0E99 1581 def +/uni0E9A 1582 def +/uni0E9B 1583 def +/uni0E9C 1584 def +/uni0E9D 1585 def +/uni0E9E 1586 def +/uni0E9F 1587 def +/uni0EA1 1588 def +/uni0EA2 1589 def +/uni0EA3 1590 def +/uni0EA5 1591 def +/uni0EA7 1592 def +/uni0EAA 1593 def +/uni0EAB 1594 def +/uni0EAD 1595 def +/uni0EAE 1596 def +/uni0EAF 1597 def +/uni0EB0 1598 def +/uni0EB1 1599 def +/uni0EB2 1600 def +/uni0EB3 1601 def +/uni0EB4 1602 def +/uni0EB5 1603 def +/uni0EB6 1604 def +/uni0EB7 1605 def +/uni0EB8 1606 def +/uni0EB9 1607 def +/uni0EBB 1608 def +/uni0EBC 1609 def +/uni0EBD 1610 def +/uni0EC0 1611 def +/uni0EC1 1612 def +/uni0EC2 1613 def +/uni0EC3 1614 def +/uni0EC4 1615 def +/uni0EC6 1616 def +/uni0EC8 1617 def +/uni0EC9 1618 def +/uni0ECA 1619 def +/uni0ECB 1620 def +/uni0ECC 1621 def +/uni0ECD 1622 def +/uni0ED0 1623 def +/uni0ED1 1624 def +/uni0ED2 1625 def +/uni0ED3 1626 def +/uni0ED4 1627 def +/uni0ED5 1628 def +/uni0ED6 1629 def +/uni0ED7 1630 def +/uni0ED8 1631 def +/uni0ED9 1632 def +/uni0EDC 1633 def +/uni0EDD 1634 def +/uni10A0 1635 def +/uni10A1 1636 def +/uni10A2 1637 def +/uni10A3 1638 def +/uni10A4 1639 def +/uni10A5 1640 def +/uni10A6 1641 def +/uni10A7 1642 def +/uni10A8 1643 def +/uni10A9 1644 def +/uni10AA 1645 def +/uni10AB 1646 def +/uni10AC 1647 def +/uni10AD 1648 def +/uni10AE 1649 def +/uni10AF 1650 def +/uni10B0 1651 def +/uni10B1 1652 def +/uni10B2 1653 def +/uni10B3 1654 def +/uni10B4 1655 def +/uni10B5 1656 def +/uni10B6 1657 def +/uni10B7 1658 def +/uni10B8 1659 def +/uni10B9 1660 def +/uni10BA 1661 def +/uni10BB 1662 def +/uni10BC 1663 def +/uni10BD 1664 def +/uni10BE 1665 def +/uni10BF 1666 def +/uni10C0 1667 def +/uni10C1 1668 def +/uni10C2 1669 def +/uni10C3 1670 def +/uni10C4 1671 def +/uni10C5 1672 def +/uni10D0 1673 def +/uni10D1 1674 def +/uni10D2 1675 def +/uni10D3 1676 def +/uni10D4 1677 def +/uni10D5 1678 def +/uni10D6 1679 def +/uni10D7 1680 def +/uni10D8 1681 def +/uni10D9 1682 def +/uni10DA 1683 def +/uni10DB 1684 def +/uni10DC 1685 def +/uni10DD 1686 def +/uni10DE 1687 def +/uni10DF 1688 def +/uni10E0 1689 def +/uni10E1 1690 def +/uni10E2 1691 def +/uni10E3 1692 def +/uni10E4 1693 def +/uni10E5 1694 def +/uni10E6 1695 def +/uni10E7 1696 def +/uni10E8 1697 def +/uni10E9 1698 def +/uni10EA 1699 def +/uni10EB 1700 def +/uni10EC 1701 def +/uni10ED 1702 def +/uni10EE 1703 def +/uni10EF 1704 def +/uni10F0 1705 def +/uni10F1 1706 def +/uni10F2 1707 def +/uni10F3 1708 def +/uni10F4 1709 def +/uni10F5 1710 def +/uni10F6 1711 def +/uni10F7 1712 def +/uni10F8 1713 def +/uni10F9 1714 def +/uni10FA 1715 def +/uni10FB 1716 def +/uni10FC 1717 def +/uni1401 1718 def +/uni1402 1719 def +/uni1403 1720 def +/uni1404 1721 def +/uni1405 1722 def +/uni1406 1723 def +/uni1407 1724 def +/uni1409 1725 def +/uni140A 1726 def +/uni140B 1727 def +/uni140C 1728 def +/uni140D 1729 def +/uni140E 1730 def +/uni140F 1731 def +/uni1410 1732 def +/uni1411 1733 def +/uni1412 1734 def +/uni1413 1735 def +/uni1414 1736 def +/uni1415 1737 def +/uni1416 1738 def +/uni1417 1739 def +/uni1418 1740 def +/uni1419 1741 def +/uni141A 1742 def +/uni141B 1743 def +/uni141D 1744 def +/uni141E 1745 def +/uni141F 1746 def +/uni1420 1747 def +/uni1421 1748 def +/uni1422 1749 def +/uni1423 1750 def +/uni1424 1751 def +/uni1425 1752 def +/uni1426 1753 def +/uni1427 1754 def +/uni1428 1755 def +/uni1429 1756 def +/uni142A 1757 def +/uni142B 1758 def +/uni142C 1759 def +/uni142D 1760 def +/uni142E 1761 def +/uni142F 1762 def +/uni1430 1763 def +/uni1431 1764 def +/uni1432 1765 def +/uni1433 1766 def +/uni1434 1767 def +/uni1435 1768 def +/uni1437 1769 def +/uni1438 1770 def +/uni1439 1771 def +/uni143A 1772 def +/uni143B 1773 def +/uni143C 1774 def +/uni143D 1775 def +/uni143E 1776 def +/uni143F 1777 def +/uni1440 1778 def +/uni1441 1779 def +/uni1442 1780 def +/uni1443 1781 def +/uni1444 1782 def +/uni1445 1783 def +/uni1446 1784 def +/uni1447 1785 def +/uni1448 1786 def +/uni1449 1787 def +/uni144A 1788 def +/uni144C 1789 def +/uni144D 1790 def +/uni144E 1791 def +/uni144F 1792 def +/uni1450 1793 def +/uni1451 1794 def +/uni1452 1795 def +/uni1454 1796 def +/uni1455 1797 def +/uni1456 1798 def +/uni1457 1799 def +/uni1458 1800 def +/uni1459 1801 def +/uni145A 1802 def +/uni145B 1803 def +/uni145C 1804 def +/uni145D 1805 def +/uni145E 1806 def +/uni145F 1807 def +/uni1460 1808 def +/uni1461 1809 def +/uni1462 1810 def +/uni1463 1811 def +/uni1464 1812 def +/uni1465 1813 def +/uni1466 1814 def +/uni1467 1815 def +/uni1468 1816 def +/uni1469 1817 def +/uni146A 1818 def +/uni146B 1819 def +/uni146C 1820 def +/uni146D 1821 def +/uni146E 1822 def +/uni146F 1823 def +/uni1470 1824 def +/uni1471 1825 def +/uni1472 1826 def +/uni1473 1827 def +/uni1474 1828 def +/uni1475 1829 def +/uni1476 1830 def +/uni1477 1831 def +/uni1478 1832 def +/uni1479 1833 def +/uni147A 1834 def +/uni147B 1835 def +/uni147C 1836 def +/uni147D 1837 def +/uni147E 1838 def +/uni147F 1839 def +/uni1480 1840 def +/uni1481 1841 def +/uni1482 1842 def +/uni1483 1843 def +/uni1484 1844 def +/uni1485 1845 def +/uni1486 1846 def +/uni1487 1847 def +/uni1488 1848 def +/uni1489 1849 def +/uni148A 1850 def +/uni148B 1851 def +/uni148C 1852 def +/uni148D 1853 def +/uni148E 1854 def +/uni148F 1855 def +/uni1490 1856 def +/uni1491 1857 def +/uni1492 1858 def +/uni1493 1859 def +/uni1494 1860 def +/uni1495 1861 def +/uni1496 1862 def +/uni1497 1863 def +/uni1498 1864 def +/uni1499 1865 def +/uni149A 1866 def +/uni149B 1867 def +/uni149C 1868 def +/uni149D 1869 def +/uni149E 1870 def +/uni149F 1871 def +/uni14A0 1872 def +/uni14A1 1873 def +/uni14A2 1874 def +/uni14A3 1875 def +/uni14A4 1876 def +/uni14A5 1877 def +/uni14A6 1878 def +/uni14A7 1879 def +/uni14A8 1880 def +/uni14A9 1881 def +/uni14AA 1882 def +/uni14AB 1883 def +/uni14AC 1884 def +/uni14AD 1885 def +/uni14AE 1886 def +/uni14AF 1887 def +/uni14B0 1888 def +/uni14B1 1889 def +/uni14B2 1890 def +/uni14B3 1891 def +/uni14B4 1892 def +/uni14B5 1893 def +/uni14B6 1894 def +/uni14B7 1895 def +/uni14B8 1896 def +/uni14B9 1897 def +/uni14BA 1898 def +/uni14BB 1899 def +/uni14BC 1900 def +/uni14BD 1901 def +/uni14C0 1902 def +/uni14C1 1903 def +/uni14C2 1904 def +/uni14C3 1905 def +/uni14C4 1906 def +/uni14C5 1907 def +/uni14C6 1908 def +/uni14C7 1909 def +/uni14C8 1910 def +/uni14C9 1911 def +/uni14CA 1912 def +/uni14CB 1913 def +/uni14CC 1914 def +/uni14CD 1915 def +/uni14CE 1916 def +/uni14CF 1917 def +/uni14D0 1918 def +/uni14D1 1919 def +/uni14D2 1920 def +/uni14D3 1921 def +/uni14D4 1922 def +/uni14D5 1923 def +/uni14D6 1924 def +/uni14D7 1925 def +/uni14D8 1926 def +/uni14D9 1927 def +/uni14DA 1928 def +/uni14DB 1929 def +/uni14DC 1930 def +/uni14DD 1931 def +/uni14DE 1932 def +/uni14DF 1933 def +/uni14E0 1934 def +/uni14E1 1935 def +/uni14E2 1936 def +/uni14E3 1937 def +/uni14E4 1938 def +/uni14E5 1939 def +/uni14E6 1940 def +/uni14E7 1941 def +/uni14E8 1942 def +/uni14E9 1943 def +/uni14EA 1944 def +/uni14EC 1945 def +/uni14ED 1946 def +/uni14EE 1947 def +/uni14EF 1948 def +/uni14F0 1949 def +/uni14F1 1950 def +/uni14F2 1951 def +/uni14F3 1952 def +/uni14F4 1953 def +/uni14F5 1954 def +/uni14F6 1955 def +/uni14F7 1956 def +/uni14F8 1957 def +/uni14F9 1958 def +/uni14FA 1959 def +/uni14FB 1960 def +/uni14FC 1961 def +/uni14FD 1962 def +/uni14FE 1963 def +/uni14FF 1964 def +/uni1500 1965 def +/uni1501 1966 def +/uni1502 1967 def +/uni1503 1968 def +/uni1504 1969 def +/uni1505 1970 def +/uni1506 1971 def +/uni1507 1972 def +/uni1510 1973 def +/uni1511 1974 def +/uni1512 1975 def +/uni1513 1976 def +/uni1514 1977 def +/uni1515 1978 def +/uni1516 1979 def +/uni1517 1980 def +/uni1518 1981 def +/uni1519 1982 def +/uni151A 1983 def +/uni151B 1984 def +/uni151C 1985 def +/uni151D 1986 def +/uni151E 1987 def +/uni151F 1988 def +/uni1520 1989 def +/uni1521 1990 def +/uni1522 1991 def +/uni1523 1992 def +/uni1524 1993 def +/uni1525 1994 def +/uni1526 1995 def +/uni1527 1996 def +/uni1528 1997 def +/uni1529 1998 def +/uni152A 1999 def +/uni152B 2000 def +/uni152C 2001 def +/uni152D 2002 def +/uni152E 2003 def +/uni152F 2004 def +/uni1530 2005 def +/uni1531 2006 def +/uni1532 2007 def +/uni1533 2008 def +/uni1534 2009 def +/uni1535 2010 def +/uni1536 2011 def +/uni1537 2012 def +/uni1538 2013 def +/uni1539 2014 def +/uni153A 2015 def +/uni153B 2016 def +/uni153C 2017 def +/uni153D 2018 def +/uni153E 2019 def +/uni1540 2020 def +/uni1541 2021 def +/uni1542 2022 def +/uni1543 2023 def +/uni1544 2024 def +/uni1545 2025 def +/uni1546 2026 def +/uni1547 2027 def +/uni1548 2028 def +/uni1549 2029 def +/uni154A 2030 def +/uni154B 2031 def +/uni154C 2032 def +/uni154D 2033 def +/uni154E 2034 def +/uni154F 2035 def +/uni1550 2036 def +/uni1552 2037 def +/uni1553 2038 def +/uni1554 2039 def +/uni1555 2040 def +/uni1556 2041 def +/uni1557 2042 def +/uni1558 2043 def +/uni1559 2044 def +/uni155A 2045 def +/uni155B 2046 def +/uni155C 2047 def +/uni155D 2048 def +/uni155E 2049 def +/uni155F 2050 def +/uni1560 2051 def +/uni1561 2052 def +/uni1562 2053 def +/uni1563 2054 def +/uni1564 2055 def +/uni1565 2056 def +/uni1566 2057 def +/uni1567 2058 def +/uni1568 2059 def +/uni1569 2060 def +/uni156A 2061 def +/uni1574 2062 def +/uni1575 2063 def +/uni1576 2064 def +/uni1577 2065 def +/uni1578 2066 def +/uni1579 2067 def +/uni157A 2068 def +/uni157B 2069 def +/uni157C 2070 def +/uni157D 2071 def +/uni157E 2072 def +/uni157F 2073 def +/uni1580 2074 def +/uni1581 2075 def +/uni1582 2076 def +/uni1583 2077 def +/uni1584 2078 def +/uni1585 2079 def +/uni158A 2080 def +/uni158B 2081 def +/uni158C 2082 def +/uni158D 2083 def +/uni158E 2084 def +/uni158F 2085 def +/uni1590 2086 def +/uni1591 2087 def +/uni1592 2088 def +/uni1593 2089 def +/uni1594 2090 def +/uni1595 2091 def +/uni1596 2092 def +/uni15A0 2093 def +/uni15A1 2094 def +/uni15A2 2095 def +/uni15A3 2096 def +/uni15A4 2097 def +/uni15A5 2098 def +/uni15A6 2099 def +/uni15A7 2100 def +/uni15A8 2101 def +/uni15A9 2102 def +/uni15AA 2103 def +/uni15AB 2104 def +/uni15AC 2105 def +/uni15AD 2106 def +/uni15AE 2107 def +/uni15AF 2108 def +/uni15DE 2109 def +/uni15E1 2110 def +/uni1646 2111 def +/uni1647 2112 def +/uni166E 2113 def +/uni166F 2114 def +/uni1670 2115 def +/uni1671 2116 def +/uni1672 2117 def +/uni1673 2118 def +/uni1674 2119 def +/uni1675 2120 def +/uni1676 2121 def +/uni1680 2122 def +/uni1681 2123 def +/uni1682 2124 def +/uni1683 2125 def +/uni1684 2126 def +/uni1685 2127 def +/uni1686 2128 def +/uni1687 2129 def +/uni1688 2130 def +/uni1689 2131 def +/uni168A 2132 def +/uni168B 2133 def +/uni168C 2134 def +/uni168D 2135 def +/uni168E 2136 def +/uni168F 2137 def +/uni1690 2138 def +/uni1691 2139 def +/uni1692 2140 def +/uni1693 2141 def +/uni1694 2142 def +/uni1695 2143 def +/uni1696 2144 def +/uni1697 2145 def +/uni1698 2146 def +/uni1699 2147 def +/uni169A 2148 def +/uni169B 2149 def +/uni169C 2150 def +/uni1D00 2151 def +/uni1D01 2152 def +/uni1D02 2153 def +/uni1D03 2154 def +/uni1D04 2155 def +/uni1D05 2156 def +/uni1D06 2157 def +/uni1D07 2158 def +/uni1D08 2159 def +/uni1D09 2160 def +/uni1D0A 2161 def +/uni1D0B 2162 def +/uni1D0C 2163 def +/uni1D0D 2164 def +/uni1D0E 2165 def +/uni1D0F 2166 def +/uni1D10 2167 def +/uni1D11 2168 def +/uni1D12 2169 def +/uni1D13 2170 def +/uni1D14 2171 def +/uni1D16 2172 def +/uni1D17 2173 def +/uni1D18 2174 def +/uni1D19 2175 def +/uni1D1A 2176 def +/uni1D1B 2177 def +/uni1D1C 2178 def +/uni1D1D 2179 def +/uni1D1E 2180 def +/uni1D1F 2181 def +/uni1D20 2182 def +/uni1D21 2183 def +/uni1D22 2184 def +/uni1D23 2185 def +/uni1D26 2186 def +/uni1D27 2187 def +/uni1D28 2188 def +/uni1D29 2189 def +/uni1D2A 2190 def +/uni1D2B 2191 def +/uni1D2C 2192 def +/uni1D2D 2193 def +/uni1D2E 2194 def +/uni1D30 2195 def +/uni1D31 2196 def +/uni1D32 2197 def +/uni1D33 2198 def +/uni1D34 2199 def +/uni1D35 2200 def +/uni1D36 2201 def +/uni1D37 2202 def +/uni1D38 2203 def +/uni1D39 2204 def +/uni1D3A 2205 def +/uni1D3B 2206 def +/uni1D3C 2207 def +/uni1D3D 2208 def +/uni1D3E 2209 def +/uni1D3F 2210 def +/uni1D40 2211 def +/uni1D41 2212 def +/uni1D42 2213 def +/uni1D43 2214 def +/uni1D44 2215 def +/uni1D45 2216 def +/uni1D46 2217 def +/uni1D47 2218 def +/uni1D48 2219 def +/uni1D49 2220 def +/uni1D4A 2221 def +/uni1D4B 2222 def +/uni1D4C 2223 def +/uni1D4D 2224 def +/uni1D4E 2225 def +/uni1D4F 2226 def +/uni1D50 2227 def +/uni1D51 2228 def +/uni1D52 2229 def +/uni1D53 2230 def +/uni1D54 2231 def +/uni1D55 2232 def +/uni1D56 2233 def +/uni1D57 2234 def +/uni1D58 2235 def +/uni1D59 2236 def +/uni1D5A 2237 def +/uni1D5B 2238 def +/uni1D5D 2239 def +/uni1D5E 2240 def +/uni1D5F 2241 def +/uni1D60 2242 def +/uni1D61 2243 def +/uni1D62 2244 def +/uni1D63 2245 def +/uni1D64 2246 def +/uni1D65 2247 def +/uni1D66 2248 def +/uni1D67 2249 def +/uni1D68 2250 def +/uni1D69 2251 def +/uni1D6A 2252 def +/uni1D77 2253 def +/uni1D78 2254 def +/uni1D7B 2255 def +/uni1D7D 2256 def +/uni1D85 2257 def +/uni1D9B 2258 def +/uni1D9C 2259 def +/uni1D9D 2260 def +/uni1D9E 2261 def +/uni1D9F 2262 def +/uni1DA0 2263 def +/uni1DA1 2264 def +/uni1DA2 2265 def +/uni1DA3 2266 def +/uni1DA4 2267 def +/uni1DA5 2268 def +/uni1DA6 2269 def +/uni1DA7 2270 def +/uni1DA8 2271 def +/uni1DA9 2272 def +/uni1DAA 2273 def +/uni1DAB 2274 def +/uni1DAC 2275 def +/uni1DAD 2276 def +/uni1DAE 2277 def +/uni1DAF 2278 def +/uni1DB0 2279 def +/uni1DB1 2280 def +/uni1DB2 2281 def +/uni1DB3 2282 def +/uni1DB4 2283 def +/uni1DB5 2284 def +/uni1DB6 2285 def +/uni1DB7 2286 def +/uni1DB8 2287 def +/uni1DB9 2288 def +/uni1DBA 2289 def +/uni1DBB 2290 def +/uni1DBC 2291 def +/uni1DBD 2292 def +/uni1DBE 2293 def +/uni1DBF 2294 def +/uni1DC4 2295 def +/uni1DC5 2296 def +/uni1DC6 2297 def +/uni1DC7 2298 def +/uni1DC8 2299 def +/uni1DC9 2300 def +/uni1E00 2301 def +/uni1E01 2302 def +/uni1E02 2303 def +/uni1E03 2304 def +/uni1E04 2305 def +/uni1E05 2306 def +/uni1E06 2307 def +/uni1E07 2308 def +/uni1E08 2309 def +/uni1E09 2310 def +/uni1E0A 2311 def +/uni1E0B 2312 def +/uni1E0C 2313 def +/uni1E0D 2314 def +/uni1E0E 2315 def +/uni1E0F 2316 def +/uni1E10 2317 def +/uni1E11 2318 def +/uni1E12 2319 def +/uni1E13 2320 def +/uni1E14 2321 def +/uni1E15 2322 def +/uni1E16 2323 def +/uni1E17 2324 def +/uni1E18 2325 def +/uni1E19 2326 def +/uni1E1A 2327 def +/uni1E1B 2328 def +/uni1E1C 2329 def +/uni1E1D 2330 def +/uni1E1E 2331 def +/uni1E1F 2332 def +/uni1E20 2333 def +/uni1E21 2334 def +/uni1E22 2335 def +/uni1E23 2336 def +/uni1E24 2337 def +/uni1E25 2338 def +/uni1E26 2339 def +/uni1E27 2340 def +/uni1E28 2341 def +/uni1E29 2342 def +/uni1E2A 2343 def +/uni1E2B 2344 def +/uni1E2C 2345 def +/uni1E2D 2346 def +/uni1E2E 2347 def +/uni1E2F 2348 def +/uni1E30 2349 def +/uni1E31 2350 def +/uni1E32 2351 def +/uni1E33 2352 def +/uni1E34 2353 def +/uni1E35 2354 def +/uni1E36 2355 def +/uni1E37 2356 def +/uni1E38 2357 def +/uni1E39 2358 def +/uni1E3A 2359 def +/uni1E3B 2360 def +/uni1E3C 2361 def +/uni1E3D 2362 def +/uni1E3E 2363 def +/uni1E3F 2364 def +/uni1E40 2365 def +/uni1E41 2366 def +/uni1E42 2367 def +/uni1E43 2368 def +/uni1E44 2369 def +/uni1E45 2370 def +/uni1E46 2371 def +/uni1E47 2372 def +/uni1E48 2373 def +/uni1E49 2374 def +/uni1E4A 2375 def +/uni1E4B 2376 def +/uni1E4C 2377 def +/uni1E4D 2378 def +/uni1E4E 2379 def +/uni1E4F 2380 def +/uni1E50 2381 def +/uni1E51 2382 def +/uni1E52 2383 def +/uni1E53 2384 def +/uni1E54 2385 def +/uni1E55 2386 def +/uni1E56 2387 def +/uni1E57 2388 def +/uni1E58 2389 def +/uni1E59 2390 def +/uni1E5A 2391 def +/uni1E5B 2392 def +/uni1E5C 2393 def +/uni1E5D 2394 def +/uni1E5E 2395 def +/uni1E5F 2396 def +/uni1E60 2397 def +/uni1E61 2398 def +/uni1E62 2399 def +/uni1E63 2400 def +/uni1E64 2401 def +/uni1E65 2402 def +/uni1E66 2403 def +/uni1E67 2404 def +/uni1E68 2405 def +/uni1E69 2406 def +/uni1E6A 2407 def +/uni1E6B 2408 def +/uni1E6C 2409 def +/uni1E6D 2410 def +/uni1E6E 2411 def +/uni1E6F 2412 def +/uni1E70 2413 def +/uni1E71 2414 def +/uni1E72 2415 def +/uni1E73 2416 def +/uni1E74 2417 def +/uni1E75 2418 def +/uni1E76 2419 def +/uni1E77 2420 def +/uni1E78 2421 def +/uni1E79 2422 def +/uni1E7A 2423 def +/uni1E7B 2424 def +/uni1E7C 2425 def +/uni1E7D 2426 def +/uni1E7E 2427 def +/uni1E7F 2428 def +/Wgrave 2429 def +/wgrave 2430 def +/Wacute 2431 def +/wacute 2432 def +/Wdieresis 2433 def +/wdieresis 2434 def +/uni1E86 2435 def +/uni1E87 2436 def +/uni1E88 2437 def +/uni1E89 2438 def +/uni1E8A 2439 def +/uni1E8B 2440 def +/uni1E8C 2441 def +/uni1E8D 2442 def +/uni1E8E 2443 def +/uni1E8F 2444 def +/uni1E90 2445 def +/uni1E91 2446 def +/uni1E92 2447 def +/uni1E93 2448 def +/uni1E94 2449 def +/uni1E95 2450 def +/uni1E96 2451 def +/uni1E97 2452 def +/uni1E98 2453 def +/uni1E99 2454 def +/uni1E9A 2455 def +/uni1E9B 2456 def +/uni1E9C 2457 def +/uni1E9D 2458 def +/uni1E9E 2459 def +/uni1E9F 2460 def +/uni1EA0 2461 def +/uni1EA1 2462 def +/uni1EA2 2463 def +/uni1EA3 2464 def +/uni1EA4 2465 def +/uni1EA5 2466 def +/uni1EA6 2467 def +/uni1EA7 2468 def +/uni1EA8 2469 def +/uni1EA9 2470 def +/uni1EAA 2471 def +/uni1EAB 2472 def +/uni1EAC 2473 def +/uni1EAD 2474 def +/uni1EAE 2475 def +/uni1EAF 2476 def +/uni1EB0 2477 def +/uni1EB1 2478 def +/uni1EB2 2479 def +/uni1EB3 2480 def +/uni1EB4 2481 def +/uni1EB5 2482 def +/uni1EB6 2483 def +/uni1EB7 2484 def +/uni1EB8 2485 def +/uni1EB9 2486 def +/uni1EBA 2487 def +/uni1EBB 2488 def +/uni1EBC 2489 def +/uni1EBD 2490 def +/uni1EBE 2491 def +/uni1EBF 2492 def +/uni1EC0 2493 def +/uni1EC1 2494 def +/uni1EC2 2495 def +/uni1EC3 2496 def +/uni1EC4 2497 def +/uni1EC5 2498 def +/uni1EC6 2499 def +/uni1EC7 2500 def +/uni1EC8 2501 def +/uni1EC9 2502 def +/uni1ECA 2503 def +/uni1ECB 2504 def +/uni1ECC 2505 def +/uni1ECD 2506 def +/uni1ECE 2507 def +/uni1ECF 2508 def +/uni1ED0 2509 def +/uni1ED1 2510 def +/uni1ED2 2511 def +/uni1ED3 2512 def +/uni1ED4 2513 def +/uni1ED5 2514 def +/uni1ED6 2515 def +/uni1ED7 2516 def +/uni1ED8 2517 def +/uni1ED9 2518 def +/uni1EDA 2519 def +/uni1EDB 2520 def +/uni1EDC 2521 def +/uni1EDD 2522 def +/uni1EDE 2523 def +/uni1EDF 2524 def +/uni1EE0 2525 def +/uni1EE1 2526 def +/uni1EE2 2527 def +/uni1EE3 2528 def +/uni1EE4 2529 def +/uni1EE5 2530 def +/uni1EE6 2531 def +/uni1EE7 2532 def +/uni1EE8 2533 def +/uni1EE9 2534 def +/uni1EEA 2535 def +/uni1EEB 2536 def +/uni1EEC 2537 def +/uni1EED 2538 def +/uni1EEE 2539 def +/uni1EEF 2540 def +/uni1EF0 2541 def +/uni1EF1 2542 def +/Ygrave 2543 def +/ygrave 2544 def +/uni1EF4 2545 def +/uni1EF5 2546 def +/uni1EF6 2547 def +/uni1EF7 2548 def +/uni1EF8 2549 def +/uni1EF9 2550 def +/uni1EFA 2551 def +/uni1EFB 2552 def +/uni1F00 2553 def +/uni1F01 2554 def +/uni1F02 2555 def +/uni1F03 2556 def +/uni1F04 2557 def +/uni1F05 2558 def +/uni1F06 2559 def +/uni1F07 2560 def +/uni1F08 2561 def +/uni1F09 2562 def +/uni1F0A 2563 def +/uni1F0B 2564 def +/uni1F0C 2565 def +/uni1F0D 2566 def +/uni1F0E 2567 def +/uni1F0F 2568 def +/uni1F10 2569 def +/uni1F11 2570 def +/uni1F12 2571 def +/uni1F13 2572 def +/uni1F14 2573 def +/uni1F15 2574 def +/uni1F18 2575 def +/uni1F19 2576 def +/uni1F1A 2577 def +/uni1F1B 2578 def +/uni1F1C 2579 def +/uni1F1D 2580 def +/uni1F20 2581 def +/uni1F21 2582 def +/uni1F22 2583 def +/uni1F23 2584 def +/uni1F24 2585 def +/uni1F25 2586 def +/uni1F26 2587 def +/uni1F27 2588 def +/uni1F28 2589 def +/uni1F29 2590 def +/uni1F2A 2591 def +/uni1F2B 2592 def +/uni1F2C 2593 def +/uni1F2D 2594 def +/uni1F2E 2595 def +/uni1F2F 2596 def +/uni1F30 2597 def +/uni1F31 2598 def +/uni1F32 2599 def +/uni1F33 2600 def +/uni1F34 2601 def +/uni1F35 2602 def +/uni1F36 2603 def +/uni1F37 2604 def +/uni1F38 2605 def +/uni1F39 2606 def +/uni1F3A 2607 def +/uni1F3B 2608 def +/uni1F3C 2609 def +/uni1F3D 2610 def +/uni1F3E 2611 def +/uni1F3F 2612 def +/uni1F40 2613 def +/uni1F41 2614 def +/uni1F42 2615 def +/uni1F43 2616 def +/uni1F44 2617 def +/uni1F45 2618 def +/uni1F48 2619 def +/uni1F49 2620 def +/uni1F4A 2621 def +/uni1F4B 2622 def +/uni1F4C 2623 def +/uni1F4D 2624 def +/uni1F50 2625 def +/uni1F51 2626 def +/uni1F52 2627 def +/uni1F53 2628 def +/uni1F54 2629 def +/uni1F55 2630 def +/uni1F56 2631 def +/uni1F57 2632 def +/uni1F59 2633 def +/uni1F5B 2634 def +/uni1F5D 2635 def +/uni1F5F 2636 def +/uni1F60 2637 def +/uni1F61 2638 def +/uni1F62 2639 def +/uni1F63 2640 def +/uni1F64 2641 def +/uni1F65 2642 def +/uni1F66 2643 def +/uni1F67 2644 def +/uni1F68 2645 def +/uni1F69 2646 def +/uni1F6A 2647 def +/uni1F6B 2648 def +/uni1F6C 2649 def +/uni1F6D 2650 def +/uni1F6E 2651 def +/uni1F6F 2652 def +/uni1F70 2653 def +/uni1F71 2654 def +/uni1F72 2655 def +/uni1F73 2656 def +/uni1F74 2657 def +/uni1F75 2658 def +/uni1F76 2659 def +/uni1F77 2660 def +/uni1F78 2661 def +/uni1F79 2662 def +/uni1F7A 2663 def +/uni1F7B 2664 def +/uni1F7C 2665 def +/uni1F7D 2666 def +/uni1F80 2667 def +/uni1F81 2668 def +/uni1F82 2669 def +/uni1F83 2670 def +/uni1F84 2671 def +/uni1F85 2672 def +/uni1F86 2673 def +/uni1F87 2674 def +/uni1F88 2675 def +/uni1F89 2676 def +/uni1F8A 2677 def +/uni1F8B 2678 def +/uni1F8C 2679 def +/uni1F8D 2680 def +/uni1F8E 2681 def +/uni1F8F 2682 def +/uni1F90 2683 def +/uni1F91 2684 def +/uni1F92 2685 def +/uni1F93 2686 def +/uni1F94 2687 def +/uni1F95 2688 def +/uni1F96 2689 def +/uni1F97 2690 def +/uni1F98 2691 def +/uni1F99 2692 def +/uni1F9A 2693 def +/uni1F9B 2694 def +/uni1F9C 2695 def +/uni1F9D 2696 def +/uni1F9E 2697 def +/uni1F9F 2698 def +/uni1FA0 2699 def +/uni1FA1 2700 def +/uni1FA2 2701 def +/uni1FA3 2702 def +/uni1FA4 2703 def +/uni1FA5 2704 def +/uni1FA6 2705 def +/uni1FA7 2706 def +/uni1FA8 2707 def +/uni1FA9 2708 def +/uni1FAA 2709 def +/uni1FAB 2710 def +/uni1FAC 2711 def +/uni1FAD 2712 def +/uni1FAE 2713 def +/uni1FAF 2714 def +/uni1FB0 2715 def +/uni1FB1 2716 def +/uni1FB2 2717 def +/uni1FB3 2718 def +/uni1FB4 2719 def +/uni1FB6 2720 def +/uni1FB7 2721 def +/uni1FB8 2722 def +/uni1FB9 2723 def +/uni1FBA 2724 def +/uni1FBB 2725 def +/uni1FBC 2726 def +/uni1FBD 2727 def +/uni1FBE 2728 def +/uni1FBF 2729 def +/uni1FC0 2730 def +/uni1FC1 2731 def +/uni1FC2 2732 def +/uni1FC3 2733 def +/uni1FC4 2734 def +/uni1FC6 2735 def +/uni1FC7 2736 def +/uni1FC8 2737 def +/uni1FC9 2738 def +/uni1FCA 2739 def +/uni1FCB 2740 def +/uni1FCC 2741 def +/uni1FCD 2742 def +/uni1FCE 2743 def +/uni1FCF 2744 def +/uni1FD0 2745 def +/uni1FD1 2746 def +/uni1FD2 2747 def +/uni1FD3 2748 def +/uni1FD6 2749 def +/uni1FD7 2750 def +/uni1FD8 2751 def +/uni1FD9 2752 def +/uni1FDA 2753 def +/uni1FDB 2754 def +/uni1FDD 2755 def +/uni1FDE 2756 def +/uni1FDF 2757 def +/uni1FE0 2758 def +/uni1FE1 2759 def +/uni1FE2 2760 def +/uni1FE3 2761 def +/uni1FE4 2762 def +/uni1FE5 2763 def +/uni1FE6 2764 def +/uni1FE7 2765 def +/uni1FE8 2766 def +/uni1FE9 2767 def +/uni1FEA 2768 def +/uni1FEB 2769 def +/uni1FEC 2770 def +/uni1FED 2771 def +/uni1FEE 2772 def +/uni1FEF 2773 def +/uni1FF2 2774 def +/uni1FF3 2775 def +/uni1FF4 2776 def +/uni1FF6 2777 def +/uni1FF7 2778 def +/uni1FF8 2779 def +/uni1FF9 2780 def +/uni1FFA 2781 def +/uni1FFB 2782 def +/uni1FFC 2783 def +/uni1FFD 2784 def +/uni1FFE 2785 def +/uni2000 2786 def +/uni2001 2787 def +/uni2002 2788 def +/uni2003 2789 def +/uni2004 2790 def +/uni2005 2791 def +/uni2006 2792 def +/uni2007 2793 def +/uni2008 2794 def +/uni2009 2795 def +/uni200A 2796 def +/uni200B 2797 def +/uni200C 2798 def +/uni200D 2799 def +/uni200E 2800 def +/uni200F 2801 def +/uni2010 2802 def +/uni2011 2803 def +/figuredash 2804 def +/endash 2805 def +/emdash 2806 def +/uni2015 2807 def +/uni2016 2808 def +/underscoredbl 2809 def +/quoteleft 2810 def +/quoteright 2811 def +/quotesinglbase 2812 def +/quotereversed 2813 def +/quotedblleft 2814 def +/quotedblright 2815 def +/quotedblbase 2816 def +/uni201F 2817 def +/dagger 2818 def +/daggerdbl 2819 def +/bullet 2820 def +/uni2023 2821 def +/onedotenleader 2822 def +/twodotenleader 2823 def +/ellipsis 2824 def +/uni2027 2825 def +/uni2028 2826 def +/uni2029 2827 def +/uni202A 2828 def +/uni202B 2829 def +/uni202C 2830 def +/uni202D 2831 def +/uni202E 2832 def +/uni202F 2833 def +/perthousand 2834 def +/uni2031 2835 def +/minute 2836 def +/second 2837 def +/uni2034 2838 def +/uni2035 2839 def +/uni2036 2840 def +/uni2037 2841 def +/uni2038 2842 def +/guilsinglleft 2843 def +/guilsinglright 2844 def +/uni203B 2845 def +/exclamdbl 2846 def +/uni203D 2847 def +/uni203E 2848 def +/uni203F 2849 def +/uni2040 2850 def +/uni2041 2851 def +/uni2042 2852 def +/uni2043 2853 def +/fraction 2854 def +/uni2045 2855 def +/uni2046 2856 def +/uni2047 2857 def +/uni2048 2858 def +/uni2049 2859 def +/uni204A 2860 def +/uni204B 2861 def +/uni204C 2862 def +/uni204D 2863 def +/uni204E 2864 def +/uni204F 2865 def +/uni2050 2866 def +/uni2051 2867 def +/uni2052 2868 def +/uni2053 2869 def +/uni2054 2870 def +/uni2055 2871 def +/uni2056 2872 def +/uni2057 2873 def +/uni2058 2874 def +/uni2059 2875 def +/uni205A 2876 def +/uni205B 2877 def +/uni205C 2878 def +/uni205D 2879 def +/uni205E 2880 def +/uni205F 2881 def +/uni2060 2882 def +/uni2061 2883 def +/uni2062 2884 def +/uni2063 2885 def +/uni2064 2886 def +/uni206A 2887 def +/uni206B 2888 def +/uni206C 2889 def +/uni206D 2890 def +/uni206E 2891 def +/uni206F 2892 def +/uni2070 2893 def +/uni2071 2894 def +/uni2074 2895 def +/uni2075 2896 def +/uni2076 2897 def +/uni2077 2898 def +/uni2078 2899 def +/uni2079 2900 def +/uni207A 2901 def +/uni207B 2902 def +/uni207C 2903 def +/uni207D 2904 def +/uni207E 2905 def +/uni207F 2906 def +/uni2080 2907 def +/uni2081 2908 def +/uni2082 2909 def +/uni2083 2910 def +/uni2084 2911 def +/uni2085 2912 def +/uni2086 2913 def +/uni2087 2914 def +/uni2088 2915 def +/uni2089 2916 def +/uni208A 2917 def +/uni208B 2918 def +/uni208C 2919 def +/uni208D 2920 def +/uni208E 2921 def +/uni2090 2922 def +/uni2091 2923 def +/uni2092 2924 def +/uni2093 2925 def +/uni2094 2926 def +/uni2095 2927 def +/uni2096 2928 def +/uni2097 2929 def +/uni2098 2930 def +/uni2099 2931 def +/uni209A 2932 def +/uni209B 2933 def +/uni209C 2934 def +/uni20A0 2935 def +/colonmonetary 2936 def +/uni20A2 2937 def +/franc 2938 def +/lira 2939 def +/uni20A5 2940 def +/uni20A6 2941 def +/peseta 2942 def +/uni20A8 2943 def +/uni20A9 2944 def +/uni20AA 2945 def +/dong 2946 def +/Euro 2947 def +/uni20AD 2948 def +/uni20AE 2949 def +/uni20AF 2950 def +/uni20B0 2951 def +/uni20B1 2952 def +/uni20B2 2953 def +/uni20B3 2954 def +/uni20B4 2955 def +/uni20B5 2956 def +/uni20B8 2957 def +/uni20B9 2958 def +/uni20BA 2959 def +/uni20BD 2960 def +/uni20D0 2961 def +/uni20D1 2962 def +/uni20D6 2963 def +/uni20D7 2964 def +/uni20DB 2965 def +/uni20DC 2966 def +/uni20E1 2967 def +/uni2100 2968 def +/uni2101 2969 def +/uni2102 2970 def +/uni2103 2971 def +/uni2104 2972 def +/uni2105 2973 def +/uni2106 2974 def +/uni2107 2975 def +/uni2108 2976 def +/uni2109 2977 def +/uni210B 2978 def +/uni210C 2979 def +/uni210D 2980 def +/uni210E 2981 def +/uni210F 2982 def +/uni2110 2983 def +/Ifraktur 2984 def +/uni2112 2985 def +/uni2113 2986 def +/uni2114 2987 def +/uni2115 2988 def +/uni2116 2989 def +/uni2117 2990 def +/weierstrass 2991 def +/uni2119 2992 def +/uni211A 2993 def +/uni211B 2994 def +/Rfraktur 2995 def +/uni211D 2996 def +/prescription 2997 def +/uni211F 2998 def +/uni2120 2999 def +/uni2121 3000 def +/trademark 3001 def +/uni2123 3002 def +/uni2124 3003 def +/uni2125 3004 def +/uni2126 3005 def +/uni2127 3006 def +/uni2128 3007 def +/uni2129 3008 def +/uni212A 3009 def +/uni212B 3010 def +/uni212C 3011 def +/uni212D 3012 def +/estimated 3013 def +/uni212F 3014 def +/uni2130 3015 def +/uni2131 3016 def +/uni2132 3017 def +/uni2133 3018 def +/uni2134 3019 def +/aleph 3020 def +/uni2136 3021 def +/uni2137 3022 def +/uni2138 3023 def +/uni2139 3024 def +/uni213A 3025 def +/uni213B 3026 def +/uni213C 3027 def +/uni213D 3028 def +/uni213E 3029 def +/uni213F 3030 def +/uni2140 3031 def +/uni2141 3032 def +/uni2142 3033 def +/uni2143 3034 def +/uni2144 3035 def +/uni2145 3036 def +/uni2146 3037 def +/uni2147 3038 def +/uni2148 3039 def +/uni2149 3040 def +/uni214B 3041 def +/uni214E 3042 def +/uni2150 3043 def +/uni2151 3044 def +/uni2152 3045 def +/onethird 3046 def +/twothirds 3047 def +/uni2155 3048 def +/uni2156 3049 def +/uni2157 3050 def +/uni2158 3051 def +/uni2159 3052 def +/uni215A 3053 def +/oneeighth 3054 def +/threeeighths 3055 def +/fiveeighths 3056 def +/seveneighths 3057 def +/uni215F 3058 def +/uni2160 3059 def +/uni2161 3060 def +/uni2162 3061 def +/uni2163 3062 def +/uni2164 3063 def +/uni2165 3064 def +/uni2166 3065 def +/uni2167 3066 def +/uni2168 3067 def +/uni2169 3068 def +/uni216A 3069 def +/uni216B 3070 def +/uni216C 3071 def +/uni216D 3072 def +/uni216E 3073 def +/uni216F 3074 def +/uni2170 3075 def +/uni2171 3076 def +/uni2172 3077 def +/uni2173 3078 def +/uni2174 3079 def +/uni2175 3080 def +/uni2176 3081 def +/uni2177 3082 def +/uni2178 3083 def +/uni2179 3084 def +/uni217A 3085 def +/uni217B 3086 def +/uni217C 3087 def +/uni217D 3088 def +/uni217E 3089 def +/uni217F 3090 def +/uni2180 3091 def +/uni2181 3092 def +/uni2182 3093 def +/uni2183 3094 def +/uni2184 3095 def +/uni2185 3096 def +/uni2189 3097 def +/arrowleft 3098 def +/arrowup 3099 def +/arrowright 3100 def +/arrowdown 3101 def +/arrowboth 3102 def +/arrowupdn 3103 def +/uni2196 3104 def +/uni2197 3105 def +/uni2198 3106 def +/uni2199 3107 def +/uni219A 3108 def +/uni219B 3109 def +/uni219C 3110 def +/uni219D 3111 def +/uni219E 3112 def +/uni219F 3113 def +/uni21A0 3114 def +/uni21A1 3115 def +/uni21A2 3116 def +/uni21A3 3117 def +/uni21A4 3118 def +/uni21A5 3119 def +/uni21A6 3120 def +/uni21A7 3121 def +/arrowupdnbse 3122 def +/uni21A9 3123 def +/uni21AA 3124 def +/uni21AB 3125 def +/uni21AC 3126 def +/uni21AD 3127 def +/uni21AE 3128 def +/uni21AF 3129 def +/uni21B0 3130 def +/uni21B1 3131 def +/uni21B2 3132 def +/uni21B3 3133 def +/uni21B4 3134 def +/carriagereturn 3135 def +/uni21B6 3136 def +/uni21B7 3137 def +/uni21B8 3138 def +/uni21B9 3139 def +/uni21BA 3140 def +/uni21BB 3141 def +/uni21BC 3142 def +/uni21BD 3143 def +/uni21BE 3144 def +/uni21BF 3145 def +/uni21C0 3146 def +/uni21C1 3147 def +/uni21C2 3148 def +/uni21C3 3149 def +/uni21C4 3150 def +/uni21C5 3151 def +/uni21C6 3152 def +/uni21C7 3153 def +/uni21C8 3154 def +/uni21C9 3155 def +/uni21CA 3156 def +/uni21CB 3157 def +/uni21CC 3158 def +/uni21CD 3159 def +/uni21CE 3160 def +/uni21CF 3161 def +/arrowdblleft 3162 def +/arrowdblup 3163 def +/arrowdblright 3164 def +/arrowdbldown 3165 def +/arrowdblboth 3166 def +/uni21D5 3167 def +/uni21D6 3168 def +/uni21D7 3169 def +/uni21D8 3170 def +/uni21D9 3171 def +/uni21DA 3172 def +/uni21DB 3173 def +/uni21DC 3174 def +/uni21DD 3175 def +/uni21DE 3176 def +/uni21DF 3177 def +/uni21E0 3178 def +/uni21E1 3179 def +/uni21E2 3180 def +/uni21E3 3181 def +/uni21E4 3182 def +/uni21E5 3183 def +/uni21E6 3184 def +/uni21E7 3185 def +/uni21E8 3186 def +/uni21E9 3187 def +/uni21EA 3188 def +/uni21EB 3189 def +/uni21EC 3190 def +/uni21ED 3191 def +/uni21EE 3192 def +/uni21EF 3193 def +/uni21F0 3194 def +/uni21F1 3195 def +/uni21F2 3196 def +/uni21F3 3197 def +/uni21F4 3198 def +/uni21F5 3199 def +/uni21F6 3200 def +/uni21F7 3201 def +/uni21F8 3202 def +/uni21F9 3203 def +/uni21FA 3204 def +/uni21FB 3205 def +/uni21FC 3206 def +/uni21FD 3207 def +/uni21FE 3208 def +/uni21FF 3209 def +/universal 3210 def +/uni2201 3211 def +/partialdiff 3212 def +/existential 3213 def +/uni2204 3214 def +/emptyset 3215 def +/Delta 3216 def +/gradient 3217 def +/element 3218 def +/notelement 3219 def +/uni220A 3220 def +/suchthat 3221 def +/uni220C 3222 def +/uni220D 3223 def +/uni220E 3224 def +/product 3225 def +/uni2210 3226 def +/summation 3227 def +/minus 3228 def +/uni2213 3229 def +/uni2214 3230 def +/uni2215 3231 def +/uni2216 3232 def +/asteriskmath 3233 def +/uni2218 3234 def +/uni2219 3235 def +/radical 3236 def +/uni221B 3237 def +/uni221C 3238 def +/proportional 3239 def +/infinity 3240 def +/orthogonal 3241 def +/angle 3242 def +/uni2221 3243 def +/uni2222 3244 def +/uni2223 3245 def +/uni2224 3246 def +/uni2225 3247 def +/uni2226 3248 def +/logicaland 3249 def +/logicalor 3250 def +/intersection 3251 def +/union 3252 def +/integral 3253 def +/uni222C 3254 def +/uni222D 3255 def +/uni222E 3256 def +/uni222F 3257 def +/uni2230 3258 def +/uni2231 3259 def +/uni2232 3260 def +/uni2233 3261 def +/therefore 3262 def +/uni2235 3263 def +/uni2236 3264 def +/uni2237 3265 def +/uni2238 3266 def +/uni2239 3267 def +/uni223A 3268 def +/uni223B 3269 def +/similar 3270 def +/uni223D 3271 def +/uni223E 3272 def +/uni223F 3273 def +/uni2240 3274 def +/uni2241 3275 def +/uni2242 3276 def +/uni2243 3277 def +/uni2244 3278 def +/congruent 3279 def +/uni2246 3280 def +/uni2247 3281 def +/approxequal 3282 def +/uni2249 3283 def +/uni224A 3284 def +/uni224B 3285 def +/uni224C 3286 def +/uni224D 3287 def +/uni224E 3288 def +/uni224F 3289 def +/uni2250 3290 def +/uni2251 3291 def +/uni2252 3292 def +/uni2253 3293 def +/uni2254 3294 def +/uni2255 3295 def +/uni2256 3296 def +/uni2257 3297 def +/uni2258 3298 def +/uni2259 3299 def +/uni225A 3300 def +/uni225B 3301 def +/uni225C 3302 def +/uni225D 3303 def +/uni225E 3304 def +/uni225F 3305 def +/notequal 3306 def +/equivalence 3307 def +/uni2262 3308 def +/uni2263 3309 def +/lessequal 3310 def +/greaterequal 3311 def +/uni2266 3312 def +/uni2267 3313 def +/uni2268 3314 def +/uni2269 3315 def +/uni226A 3316 def +/uni226B 3317 def +/uni226C 3318 def +/uni226D 3319 def +/uni226E 3320 def +/uni226F 3321 def +/uni2270 3322 def +/uni2271 3323 def +/uni2272 3324 def +/uni2273 3325 def +/uni2274 3326 def +/uni2275 3327 def +/uni2276 3328 def +/uni2277 3329 def +/uni2278 3330 def +/uni2279 3331 def +/uni227A 3332 def +/uni227B 3333 def +/uni227C 3334 def +/uni227D 3335 def +/uni227E 3336 def +/uni227F 3337 def +/uni2280 3338 def +/uni2281 3339 def +/propersubset 3340 def +/propersuperset 3341 def +/notsubset 3342 def +/uni2285 3343 def +/reflexsubset 3344 def +/reflexsuperset 3345 def +/uni2288 3346 def +/uni2289 3347 def +/uni228A 3348 def +/uni228B 3349 def +/uni228C 3350 def +/uni228D 3351 def +/uni228E 3352 def +/uni228F 3353 def +/uni2290 3354 def +/uni2291 3355 def +/uni2292 3356 def +/uni2293 3357 def +/uni2294 3358 def +/circleplus 3359 def +/uni2296 3360 def +/circlemultiply 3361 def +/uni2298 3362 def +/uni2299 3363 def +/uni229A 3364 def +/uni229B 3365 def +/uni229C 3366 def +/uni229D 3367 def +/uni229E 3368 def +/uni229F 3369 def +/uni22A0 3370 def +/uni22A1 3371 def +/uni22A2 3372 def +/uni22A3 3373 def +/uni22A4 3374 def +/perpendicular 3375 def +/uni22A6 3376 def +/uni22A7 3377 def +/uni22A8 3378 def +/uni22A9 3379 def +/uni22AA 3380 def +/uni22AB 3381 def +/uni22AC 3382 def +/uni22AD 3383 def +/uni22AE 3384 def +/uni22AF 3385 def +/uni22B0 3386 def +/uni22B1 3387 def +/uni22B2 3388 def +/uni22B3 3389 def +/uni22B4 3390 def +/uni22B5 3391 def +/uni22B6 3392 def +/uni22B7 3393 def +/uni22B8 3394 def +/uni22B9 3395 def +/uni22BA 3396 def +/uni22BB 3397 def +/uni22BC 3398 def +/uni22BD 3399 def +/uni22BE 3400 def +/uni22BF 3401 def +/uni22C0 3402 def +/uni22C1 3403 def +/uni22C2 3404 def +/uni22C3 3405 def +/uni22C4 3406 def +/dotmath 3407 def +/uni22C6 3408 def +/uni22C7 3409 def +/uni22C8 3410 def +/uni22C9 3411 def +/uni22CA 3412 def +/uni22CB 3413 def +/uni22CC 3414 def +/uni22CD 3415 def +/uni22CE 3416 def +/uni22CF 3417 def +/uni22D0 3418 def +/uni22D1 3419 def +/uni22D2 3420 def +/uni22D3 3421 def +/uni22D4 3422 def +/uni22D5 3423 def +/uni22D6 3424 def +/uni22D7 3425 def +/uni22D8 3426 def +/uni22D9 3427 def +/uni22DA 3428 def +/uni22DB 3429 def +/uni22DC 3430 def +/uni22DD 3431 def +/uni22DE 3432 def +/uni22DF 3433 def +/uni22E0 3434 def +/uni22E1 3435 def +/uni22E2 3436 def +/uni22E3 3437 def +/uni22E4 3438 def +/uni22E5 3439 def +/uni22E6 3440 def +/uni22E7 3441 def +/uni22E8 3442 def +/uni22E9 3443 def +/uni22EA 3444 def +/uni22EB 3445 def +/uni22EC 3446 def +/uni22ED 3447 def +/uni22EE 3448 def +/uni22EF 3449 def +/uni22F0 3450 def +/uni22F1 3451 def +/uni22F2 3452 def +/uni22F3 3453 def +/uni22F4 3454 def +/uni22F5 3455 def +/uni22F6 3456 def +/uni22F7 3457 def +/uni22F8 3458 def +/uni22F9 3459 def +/uni22FA 3460 def +/uni22FB 3461 def +/uni22FC 3462 def +/uni22FD 3463 def +/uni22FE 3464 def +/uni22FF 3465 def +/uni2300 3466 def +/uni2301 3467 def +/house 3468 def +/uni2303 3469 def +/uni2304 3470 def +/uni2305 3471 def +/uni2306 3472 def +/uni2307 3473 def +/uni2308 3474 def +/uni2309 3475 def +/uni230A 3476 def +/uni230B 3477 def +/uni230C 3478 def +/uni230D 3479 def +/uni230E 3480 def +/uni230F 3481 def +/revlogicalnot 3482 def +/uni2311 3483 def +/uni2318 3484 def +/uni2319 3485 def +/uni231C 3486 def +/uni231D 3487 def +/uni231E 3488 def +/uni231F 3489 def +/integraltp 3490 def +/integralbt 3491 def +/uni2324 3492 def +/uni2325 3493 def +/uni2326 3494 def +/uni2327 3495 def +/uni2328 3496 def +/uni232B 3497 def +/uni232C 3498 def +/uni2373 3499 def +/uni2374 3500 def +/uni2375 3501 def +/uni237A 3502 def +/uni237D 3503 def +/uni2387 3504 def +/uni2394 3505 def +/uni239B 3506 def +/uni239C 3507 def +/uni239D 3508 def +/uni239E 3509 def +/uni239F 3510 def +/uni23A0 3511 def +/uni23A1 3512 def +/uni23A2 3513 def +/uni23A3 3514 def +/uni23A4 3515 def +/uni23A5 3516 def +/uni23A6 3517 def +/uni23A7 3518 def +/uni23A8 3519 def +/uni23A9 3520 def +/uni23AA 3521 def +/uni23AB 3522 def +/uni23AC 3523 def +/uni23AD 3524 def +/uni23AE 3525 def +/uni23CE 3526 def +/uni23CF 3527 def +/uni23E3 3528 def +/uni23E5 3529 def +/uni23E8 3530 def +/uni2422 3531 def +/uni2423 3532 def +/uni2460 3533 def +/uni2461 3534 def +/uni2462 3535 def +/uni2463 3536 def +/uni2464 3537 def +/uni2465 3538 def +/uni2466 3539 def +/uni2467 3540 def +/uni2468 3541 def +/uni2469 3542 def +/SF100000 3543 def +/uni2501 3544 def +/SF110000 3545 def +/uni2503 3546 def +/uni2504 3547 def +/uni2505 3548 def +/uni2506 3549 def +/uni2507 3550 def +/uni2508 3551 def +/uni2509 3552 def +/uni250A 3553 def +/uni250B 3554 def +/SF010000 3555 def +/uni250D 3556 def +/uni250E 3557 def +/uni250F 3558 def +/SF030000 3559 def +/uni2511 3560 def +/uni2512 3561 def +/uni2513 3562 def +/SF020000 3563 def +/uni2515 3564 def +/uni2516 3565 def +/uni2517 3566 def +/SF040000 3567 def +/uni2519 3568 def +/uni251A 3569 def +/uni251B 3570 def +/SF080000 3571 def +/uni251D 3572 def +/uni251E 3573 def +/uni251F 3574 def +/uni2520 3575 def +/uni2521 3576 def +/uni2522 3577 def +/uni2523 3578 def +/SF090000 3579 def +/uni2525 3580 def +/uni2526 3581 def +/uni2527 3582 def +/uni2528 3583 def +/uni2529 3584 def +/uni252A 3585 def +/uni252B 3586 def +/SF060000 3587 def +/uni252D 3588 def +/uni252E 3589 def +/uni252F 3590 def +/uni2530 3591 def +/uni2531 3592 def +/uni2532 3593 def +/uni2533 3594 def +/SF070000 3595 def +/uni2535 3596 def +/uni2536 3597 def +/uni2537 3598 def +/uni2538 3599 def +/uni2539 3600 def +/uni253A 3601 def +/uni253B 3602 def +/SF050000 3603 def +/uni253D 3604 def +/uni253E 3605 def +/uni253F 3606 def +/uni2540 3607 def +/uni2541 3608 def +/uni2542 3609 def +/uni2543 3610 def +/uni2544 3611 def +/uni2545 3612 def +/uni2546 3613 def +/uni2547 3614 def +/uni2548 3615 def +/uni2549 3616 def +/uni254A 3617 def +/uni254B 3618 def +/uni254C 3619 def +/uni254D 3620 def +/uni254E 3621 def +/uni254F 3622 def +/SF430000 3623 def +/SF240000 3624 def +/SF510000 3625 def +/SF520000 3626 def +/SF390000 3627 def +/SF220000 3628 def +/SF210000 3629 def +/SF250000 3630 def +/SF500000 3631 def +/SF490000 3632 def +/SF380000 3633 def +/SF280000 3634 def +/SF270000 3635 def +/SF260000 3636 def +/SF360000 3637 def +/SF370000 3638 def +/SF420000 3639 def +/SF190000 3640 def +/SF200000 3641 def +/SF230000 3642 def +/SF470000 3643 def +/SF480000 3644 def +/SF410000 3645 def +/SF450000 3646 def +/SF460000 3647 def +/SF400000 3648 def +/SF540000 3649 def +/SF530000 3650 def +/SF440000 3651 def +/uni256D 3652 def +/uni256E 3653 def +/uni256F 3654 def +/uni2570 3655 def +/uni2571 3656 def +/uni2572 3657 def +/uni2573 3658 def +/uni2574 3659 def +/uni2575 3660 def +/uni2576 3661 def +/uni2577 3662 def +/uni2578 3663 def +/uni2579 3664 def +/uni257A 3665 def +/uni257B 3666 def +/uni257C 3667 def +/uni257D 3668 def +/uni257E 3669 def +/uni257F 3670 def +/upblock 3671 def +/uni2581 3672 def +/uni2582 3673 def +/uni2583 3674 def +/dnblock 3675 def +/uni2585 3676 def +/uni2586 3677 def +/uni2587 3678 def +/block 3679 def +/uni2589 3680 def +/uni258A 3681 def +/uni258B 3682 def +/lfblock 3683 def +/uni258D 3684 def +/uni258E 3685 def +/uni258F 3686 def +/rtblock 3687 def +/ltshade 3688 def +/shade 3689 def +/dkshade 3690 def +/uni2594 3691 def +/uni2595 3692 def +/uni2596 3693 def +/uni2597 3694 def +/uni2598 3695 def +/uni2599 3696 def +/uni259A 3697 def +/uni259B 3698 def +/uni259C 3699 def +/uni259D 3700 def +/uni259E 3701 def +/uni259F 3702 def +/filledbox 3703 def +/H22073 3704 def +/uni25A2 3705 def +/uni25A3 3706 def +/uni25A4 3707 def +/uni25A5 3708 def +/uni25A6 3709 def +/uni25A7 3710 def +/uni25A8 3711 def +/uni25A9 3712 def +/H18543 3713 def +/H18551 3714 def +/filledrect 3715 def +/uni25AD 3716 def +/uni25AE 3717 def +/uni25AF 3718 def +/uni25B0 3719 def +/uni25B1 3720 def +/triagup 3721 def +/uni25B3 3722 def +/uni25B4 3723 def +/uni25B5 3724 def +/uni25B6 3725 def +/uni25B7 3726 def +/uni25B8 3727 def +/uni25B9 3728 def +/triagrt 3729 def +/uni25BB 3730 def +/triagdn 3731 def +/uni25BD 3732 def +/uni25BE 3733 def +/uni25BF 3734 def +/uni25C0 3735 def +/uni25C1 3736 def +/uni25C2 3737 def +/uni25C3 3738 def +/triaglf 3739 def +/uni25C5 3740 def +/uni25C6 3741 def +/uni25C7 3742 def +/uni25C8 3743 def +/uni25C9 3744 def +/lozenge 3745 def +/circle 3746 def +/uni25CC 3747 def +/uni25CD 3748 def +/uni25CE 3749 def +/H18533 3750 def +/uni25D0 3751 def +/uni25D1 3752 def +/uni25D2 3753 def +/uni25D3 3754 def +/uni25D4 3755 def +/uni25D5 3756 def +/uni25D6 3757 def +/uni25D7 3758 def +/invbullet 3759 def +/invcircle 3760 def +/uni25DA 3761 def +/uni25DB 3762 def +/uni25DC 3763 def +/uni25DD 3764 def +/uni25DE 3765 def +/uni25DF 3766 def +/uni25E0 3767 def +/uni25E1 3768 def +/uni25E2 3769 def +/uni25E3 3770 def +/uni25E4 3771 def +/uni25E5 3772 def +/openbullet 3773 def +/uni25E7 3774 def +/uni25E8 3775 def +/uni25E9 3776 def +/uni25EA 3777 def +/uni25EB 3778 def +/uni25EC 3779 def +/uni25ED 3780 def +/uni25EE 3781 def +/uni25EF 3782 def +/uni25F0 3783 def +/uni25F1 3784 def +/uni25F2 3785 def +/uni25F3 3786 def +/uni25F4 3787 def +/uni25F5 3788 def +/uni25F6 3789 def +/uni25F7 3790 def +/uni25F8 3791 def +/uni25F9 3792 def +/uni25FA 3793 def +/uni25FB 3794 def +/uni25FC 3795 def +/uni25FD 3796 def +/uni25FE 3797 def +/uni25FF 3798 def +/uni2600 3799 def +/uni2601 3800 def +/uni2602 3801 def +/uni2603 3802 def +/uni2604 3803 def +/uni2605 3804 def +/uni2606 3805 def +/uni2607 3806 def +/uni2608 3807 def +/uni2609 3808 def +/uni260A 3809 def +/uni260B 3810 def +/uni260C 3811 def +/uni260D 3812 def +/uni260E 3813 def +/uni260F 3814 def +/uni2610 3815 def +/uni2611 3816 def +/uni2612 3817 def +/uni2613 3818 def +/uni2614 3819 def +/uni2615 3820 def +/uni2616 3821 def +/uni2617 3822 def +/uni2618 3823 def +/uni2619 3824 def +/uni261A 3825 def +/uni261B 3826 def +/uni261C 3827 def +/uni261D 3828 def +/uni261E 3829 def +/uni261F 3830 def +/uni2620 3831 def +/uni2621 3832 def +/uni2622 3833 def +/uni2623 3834 def +/uni2624 3835 def +/uni2625 3836 def +/uni2626 3837 def +/uni2627 3838 def +/uni2628 3839 def +/uni2629 3840 def +/uni262A 3841 def +/uni262B 3842 def +/uni262C 3843 def +/uni262D 3844 def +/uni262E 3845 def +/uni262F 3846 def +/uni2630 3847 def +/uni2631 3848 def +/uni2632 3849 def +/uni2633 3850 def +/uni2634 3851 def +/uni2635 3852 def +/uni2636 3853 def +/uni2637 3854 def +/uni2638 3855 def +/uni2639 3856 def +/smileface 3857 def +/invsmileface 3858 def +/sun 3859 def +/uni263D 3860 def +/uni263E 3861 def +/uni263F 3862 def +/female 3863 def +/uni2641 3864 def +/male 3865 def +/uni2643 3866 def +/uni2644 3867 def +/uni2645 3868 def +/uni2646 3869 def +/uni2647 3870 def +/uni2648 3871 def +/uni2649 3872 def +/uni264A 3873 def +/uni264B 3874 def +/uni264C 3875 def +/uni264D 3876 def +/uni264E 3877 def +/uni264F 3878 def +/uni2650 3879 def +/uni2651 3880 def +/uni2652 3881 def +/uni2653 3882 def +/uni2654 3883 def +/uni2655 3884 def +/uni2656 3885 def +/uni2657 3886 def +/uni2658 3887 def +/uni2659 3888 def +/uni265A 3889 def +/uni265B 3890 def +/uni265C 3891 def +/uni265D 3892 def +/uni265E 3893 def +/uni265F 3894 def +/spade 3895 def +/uni2661 3896 def +/uni2662 3897 def +/club 3898 def +/uni2664 3899 def +/heart 3900 def +/diamond 3901 def +/uni2667 3902 def +/uni2668 3903 def +/uni2669 3904 def +/musicalnote 3905 def +/musicalnotedbl 3906 def +/uni266C 3907 def +/uni266D 3908 def +/uni266E 3909 def +/uni266F 3910 def +/uni2670 3911 def +/uni2671 3912 def +/uni2672 3913 def +/uni2673 3914 def +/uni2674 3915 def +/uni2675 3916 def +/uni2676 3917 def +/uni2677 3918 def +/uni2678 3919 def +/uni2679 3920 def +/uni267A 3921 def +/uni267B 3922 def +/uni267C 3923 def +/uni267D 3924 def +/uni267E 3925 def +/uni267F 3926 def +/uni2680 3927 def +/uni2681 3928 def +/uni2682 3929 def +/uni2683 3930 def +/uni2684 3931 def +/uni2685 3932 def +/uni2686 3933 def +/uni2687 3934 def +/uni2688 3935 def +/uni2689 3936 def +/uni268A 3937 def +/uni268B 3938 def +/uni268C 3939 def +/uni268D 3940 def +/uni268E 3941 def +/uni268F 3942 def +/uni2690 3943 def +/uni2691 3944 def +/uni2692 3945 def +/uni2693 3946 def +/uni2694 3947 def +/uni2695 3948 def +/uni2696 3949 def +/uni2697 3950 def +/uni2698 3951 def +/uni2699 3952 def +/uni269A 3953 def +/uni269B 3954 def +/uni269C 3955 def +/uni269E 3956 def +/uni269F 3957 def +/uni26A0 3958 def +/uni26A1 3959 def +/uni26A2 3960 def +/uni26A3 3961 def +/uni26A4 3962 def +/uni26A5 3963 def +/uni26A6 3964 def +/uni26A7 3965 def +/uni26A8 3966 def +/uni26A9 3967 def +/uni26AA 3968 def +/uni26AB 3969 def +/uni26AC 3970 def +/uni26AD 3971 def +/uni26AE 3972 def +/uni26AF 3973 def +/uni26B0 3974 def +/uni26B1 3975 def +/uni26B2 3976 def +/uni26B3 3977 def +/uni26B4 3978 def +/uni26B5 3979 def +/uni26B6 3980 def +/uni26B7 3981 def +/uni26B8 3982 def +/uni26C0 3983 def +/uni26C1 3984 def +/uni26C2 3985 def +/uni26C3 3986 def +/uni26E2 3987 def +/uni2701 3988 def +/uni2702 3989 def +/uni2703 3990 def +/uni2704 3991 def +/uni2706 3992 def +/uni2707 3993 def +/uni2708 3994 def +/uni2709 3995 def +/uni270C 3996 def +/uni270D 3997 def +/uni270E 3998 def +/uni270F 3999 def +/uni2710 4000 def +/uni2711 4001 def +/uni2712 4002 def +/uni2713 4003 def +/uni2714 4004 def +/uni2715 4005 def +/uni2716 4006 def +/uni2717 4007 def +/uni2718 4008 def +/uni2719 4009 def +/uni271A 4010 def +/uni271B 4011 def +/uni271C 4012 def +/uni271D 4013 def +/uni271E 4014 def +/uni271F 4015 def +/uni2720 4016 def +/uni2721 4017 def +/uni2722 4018 def +/uni2723 4019 def +/uni2724 4020 def +/uni2725 4021 def +/uni2726 4022 def +/uni2727 4023 def +/uni2729 4024 def +/uni272A 4025 def +/uni272B 4026 def +/uni272C 4027 def +/uni272D 4028 def +/uni272E 4029 def +/uni272F 4030 def +/uni2730 4031 def +/uni2731 4032 def +/uni2732 4033 def +/uni2733 4034 def +/uni2734 4035 def +/uni2735 4036 def +/uni2736 4037 def +/uni2737 4038 def +/uni2738 4039 def +/uni2739 4040 def +/uni273A 4041 def +/uni273B 4042 def +/uni273C 4043 def +/uni273D 4044 def +/uni273E 4045 def +/uni273F 4046 def +/uni2740 4047 def +/uni2741 4048 def +/uni2742 4049 def +/uni2743 4050 def +/uni2744 4051 def +/uni2745 4052 def +/uni2746 4053 def +/uni2747 4054 def +/uni2748 4055 def +/uni2749 4056 def +/uni274A 4057 def +/uni274B 4058 def +/uni274D 4059 def +/uni274F 4060 def +/uni2750 4061 def +/uni2751 4062 def +/uni2752 4063 def +/uni2756 4064 def +/uni2758 4065 def +/uni2759 4066 def +/uni275A 4067 def +/uni275B 4068 def +/uni275C 4069 def +/uni275D 4070 def +/uni275E 4071 def +/uni2761 4072 def +/uni2762 4073 def +/uni2763 4074 def +/uni2764 4075 def +/uni2765 4076 def +/uni2766 4077 def +/uni2767 4078 def +/uni2768 4079 def +/uni2769 4080 def +/uni276A 4081 def +/uni276B 4082 def +/uni276C 4083 def +/uni276D 4084 def +/uni276E 4085 def +/uni276F 4086 def +/uni2770 4087 def +/uni2771 4088 def +/uni2772 4089 def +/uni2773 4090 def +/uni2774 4091 def +/uni2775 4092 def +/uni2776 4093 def +/uni2777 4094 def +/uni2778 4095 def +/uni2779 4096 def +/uni277A 4097 def +/uni277B 4098 def +/uni277C 4099 def +/uni277D 4100 def +/uni277E 4101 def +/uni277F 4102 def +/uni2780 4103 def +/uni2781 4104 def +/uni2782 4105 def +/uni2783 4106 def +/uni2784 4107 def +/uni2785 4108 def +/uni2786 4109 def +/uni2787 4110 def +/uni2788 4111 def +/uni2789 4112 def +/uni278A 4113 def +/uni278B 4114 def +/uni278C 4115 def +/uni278D 4116 def +/uni278E 4117 def +/uni278F 4118 def +/uni2790 4119 def +/uni2791 4120 def +/uni2792 4121 def +/uni2793 4122 def +/uni2794 4123 def +/uni2798 4124 def +/uni2799 4125 def +/uni279A 4126 def +/uni279B 4127 def +/uni279C 4128 def +/uni279D 4129 def +/uni279E 4130 def +/uni279F 4131 def +/uni27A0 4132 def +/uni27A1 4133 def +/uni27A2 4134 def +/uni27A3 4135 def +/uni27A4 4136 def +/uni27A5 4137 def +/uni27A6 4138 def +/uni27A7 4139 def +/uni27A8 4140 def +/uni27A9 4141 def +/uni27AA 4142 def +/uni27AB 4143 def +/uni27AC 4144 def +/uni27AD 4145 def +/uni27AE 4146 def +/uni27AF 4147 def +/uni27B1 4148 def +/uni27B2 4149 def +/uni27B3 4150 def +/uni27B4 4151 def +/uni27B5 4152 def +/uni27B6 4153 def +/uni27B7 4154 def +/uni27B8 4155 def +/uni27B9 4156 def +/uni27BA 4157 def +/uni27BB 4158 def +/uni27BC 4159 def +/uni27BD 4160 def +/uni27BE 4161 def +/uni27C5 4162 def +/uni27C6 4163 def +/uni27E0 4164 def +/uni27E6 4165 def +/uni27E7 4166 def +/uni27E8 4167 def +/uni27E9 4168 def +/uni27EA 4169 def +/uni27EB 4170 def +/uni27F0 4171 def +/uni27F1 4172 def +/uni27F2 4173 def +/uni27F3 4174 def +/uni27F4 4175 def +/uni27F5 4176 def +/uni27F6 4177 def +/uni27F7 4178 def +/uni27F8 4179 def +/uni27F9 4180 def +/uni27FA 4181 def +/uni27FB 4182 def +/uni27FC 4183 def +/uni27FD 4184 def +/uni27FE 4185 def +/uni27FF 4186 def +/uni2800 4187 def +/uni2801 4188 def +/uni2802 4189 def +/uni2803 4190 def +/uni2804 4191 def +/uni2805 4192 def +/uni2806 4193 def +/uni2807 4194 def +/uni2808 4195 def +/uni2809 4196 def +/uni280A 4197 def +/uni280B 4198 def +/uni280C 4199 def +/uni280D 4200 def +/uni280E 4201 def +/uni280F 4202 def +/uni2810 4203 def +/uni2811 4204 def +/uni2812 4205 def +/uni2813 4206 def +/uni2814 4207 def +/uni2815 4208 def +/uni2816 4209 def +/uni2817 4210 def +/uni2818 4211 def +/uni2819 4212 def +/uni281A 4213 def +/uni281B 4214 def +/uni281C 4215 def +/uni281D 4216 def +/uni281E 4217 def +/uni281F 4218 def +/uni2820 4219 def +/uni2821 4220 def +/uni2822 4221 def +/uni2823 4222 def +/uni2824 4223 def +/uni2825 4224 def +/uni2826 4225 def +/uni2827 4226 def +/uni2828 4227 def +/uni2829 4228 def +/uni282A 4229 def +/uni282B 4230 def +/uni282C 4231 def +/uni282D 4232 def +/uni282E 4233 def +/uni282F 4234 def +/uni2830 4235 def +/uni2831 4236 def +/uni2832 4237 def +/uni2833 4238 def +/uni2834 4239 def +/uni2835 4240 def +/uni2836 4241 def +/uni2837 4242 def +/uni2838 4243 def +/uni2839 4244 def +/uni283A 4245 def +/uni283B 4246 def +/uni283C 4247 def +/uni283D 4248 def +/uni283E 4249 def +/uni283F 4250 def +/uni2840 4251 def +/uni2841 4252 def +/uni2842 4253 def +/uni2843 4254 def +/uni2844 4255 def +/uni2845 4256 def +/uni2846 4257 def +/uni2847 4258 def +/uni2848 4259 def +/uni2849 4260 def +/uni284A 4261 def +/uni284B 4262 def +/uni284C 4263 def +/uni284D 4264 def +/uni284E 4265 def +/uni284F 4266 def +/uni2850 4267 def +/uni2851 4268 def +/uni2852 4269 def +/uni2853 4270 def +/uni2854 4271 def +/uni2855 4272 def +/uni2856 4273 def +/uni2857 4274 def +/uni2858 4275 def +/uni2859 4276 def +/uni285A 4277 def +/uni285B 4278 def +/uni285C 4279 def +/uni285D 4280 def +/uni285E 4281 def +/uni285F 4282 def +/uni2860 4283 def +/uni2861 4284 def +/uni2862 4285 def +/uni2863 4286 def +/uni2864 4287 def +/uni2865 4288 def +/uni2866 4289 def +/uni2867 4290 def +/uni2868 4291 def +/uni2869 4292 def +/uni286A 4293 def +/uni286B 4294 def +/uni286C 4295 def +/uni286D 4296 def +/uni286E 4297 def +/uni286F 4298 def +/uni2870 4299 def +/uni2871 4300 def +/uni2872 4301 def +/uni2873 4302 def +/uni2874 4303 def +/uni2875 4304 def +/uni2876 4305 def +/uni2877 4306 def +/uni2878 4307 def +/uni2879 4308 def +/uni287A 4309 def +/uni287B 4310 def +/uni287C 4311 def +/uni287D 4312 def +/uni287E 4313 def +/uni287F 4314 def +/uni2880 4315 def +/uni2881 4316 def +/uni2882 4317 def +/uni2883 4318 def +/uni2884 4319 def +/uni2885 4320 def +/uni2886 4321 def +/uni2887 4322 def +/uni2888 4323 def +/uni2889 4324 def +/uni288A 4325 def +/uni288B 4326 def +/uni288C 4327 def +/uni288D 4328 def +/uni288E 4329 def +/uni288F 4330 def +/uni2890 4331 def +/uni2891 4332 def +/uni2892 4333 def +/uni2893 4334 def +/uni2894 4335 def +/uni2895 4336 def +/uni2896 4337 def +/uni2897 4338 def +/uni2898 4339 def +/uni2899 4340 def +/uni289A 4341 def +/uni289B 4342 def +/uni289C 4343 def +/uni289D 4344 def +/uni289E 4345 def +/uni289F 4346 def +/uni28A0 4347 def +/uni28A1 4348 def +/uni28A2 4349 def +/uni28A3 4350 def +/uni28A4 4351 def +/uni28A5 4352 def +/uni28A6 4353 def +/uni28A7 4354 def +/uni28A8 4355 def +/uni28A9 4356 def +/uni28AA 4357 def +/uni28AB 4358 def +/uni28AC 4359 def +/uni28AD 4360 def +/uni28AE 4361 def +/uni28AF 4362 def +/uni28B0 4363 def +/uni28B1 4364 def +/uni28B2 4365 def +/uni28B3 4366 def +/uni28B4 4367 def +/uni28B5 4368 def +/uni28B6 4369 def +/uni28B7 4370 def +/uni28B8 4371 def +/uni28B9 4372 def +/uni28BA 4373 def +/uni28BB 4374 def +/uni28BC 4375 def +/uni28BD 4376 def +/uni28BE 4377 def +/uni28BF 4378 def +/uni28C0 4379 def +/uni28C1 4380 def +/uni28C2 4381 def +/uni28C3 4382 def +/uni28C4 4383 def +/uni28C5 4384 def +/uni28C6 4385 def +/uni28C7 4386 def +/uni28C8 4387 def +/uni28C9 4388 def +/uni28CA 4389 def +/uni28CB 4390 def +/uni28CC 4391 def +/uni28CD 4392 def +/uni28CE 4393 def +/uni28CF 4394 def +/uni28D0 4395 def +/uni28D1 4396 def +/uni28D2 4397 def +/uni28D3 4398 def +/uni28D4 4399 def +/uni28D5 4400 def +/uni28D6 4401 def +/uni28D7 4402 def +/uni28D8 4403 def +/uni28D9 4404 def +/uni28DA 4405 def +/uni28DB 4406 def +/uni28DC 4407 def +/uni28DD 4408 def +/uni28DE 4409 def +/uni28DF 4410 def +/uni28E0 4411 def +/uni28E1 4412 def +/uni28E2 4413 def +/uni28E3 4414 def +/uni28E4 4415 def +/uni28E5 4416 def +/uni28E6 4417 def +/uni28E7 4418 def +/uni28E8 4419 def +/uni28E9 4420 def +/uni28EA 4421 def +/uni28EB 4422 def +/uni28EC 4423 def +/uni28ED 4424 def +/uni28EE 4425 def +/uni28EF 4426 def +/uni28F0 4427 def +/uni28F1 4428 def +/uni28F2 4429 def +/uni28F3 4430 def +/uni28F4 4431 def +/uni28F5 4432 def +/uni28F6 4433 def +/uni28F7 4434 def +/uni28F8 4435 def +/uni28F9 4436 def +/uni28FA 4437 def +/uni28FB 4438 def +/uni28FC 4439 def +/uni28FD 4440 def +/uni28FE 4441 def +/uni28FF 4442 def +/uni2906 4443 def +/uni2907 4444 def +/uni290A 4445 def +/uni290B 4446 def +/uni2940 4447 def +/uni2941 4448 def +/uni2983 4449 def +/uni2984 4450 def +/uni29CE 4451 def +/uni29CF 4452 def +/uni29D0 4453 def +/uni29D1 4454 def +/uni29D2 4455 def +/uni29D3 4456 def +/uni29D4 4457 def +/uni29D5 4458 def +/uni29EB 4459 def +/uni29FA 4460 def +/uni29FB 4461 def +/uni2A00 4462 def +/uni2A01 4463 def +/uni2A02 4464 def +/uni2A0C 4465 def +/uni2A0D 4466 def +/uni2A0E 4467 def +/uni2A0F 4468 def +/uni2A10 4469 def +/uni2A11 4470 def +/uni2A12 4471 def +/uni2A13 4472 def +/uni2A14 4473 def +/uni2A15 4474 def +/uni2A16 4475 def +/uni2A17 4476 def +/uni2A18 4477 def +/uni2A19 4478 def +/uni2A1A 4479 def +/uni2A1B 4480 def +/uni2A1C 4481 def +/uni2A2F 4482 def +/uni2A6A 4483 def +/uni2A6B 4484 def +/uni2A7D 4485 def +/uni2A7E 4486 def +/uni2A7F 4487 def +/uni2A80 4488 def +/uni2A81 4489 def +/uni2A82 4490 def +/uni2A83 4491 def +/uni2A84 4492 def +/uni2A85 4493 def +/uni2A86 4494 def +/uni2A87 4495 def +/uni2A88 4496 def +/uni2A89 4497 def +/uni2A8A 4498 def +/uni2A8B 4499 def +/uni2A8C 4500 def +/uni2A8D 4501 def +/uni2A8E 4502 def +/uni2A8F 4503 def +/uni2A90 4504 def +/uni2A91 4505 def +/uni2A92 4506 def +/uni2A93 4507 def +/uni2A94 4508 def +/uni2A95 4509 def +/uni2A96 4510 def +/uni2A97 4511 def +/uni2A98 4512 def +/uni2A99 4513 def +/uni2A9A 4514 def +/uni2A9B 4515 def +/uni2A9C 4516 def +/uni2A9D 4517 def +/uni2A9E 4518 def +/uni2A9F 4519 def +/uni2AA0 4520 def +/uni2AAE 4521 def +/uni2AAF 4522 def +/uni2AB0 4523 def +/uni2AB1 4524 def +/uni2AB2 4525 def +/uni2AB3 4526 def +/uni2AB4 4527 def +/uni2AB5 4528 def +/uni2AB6 4529 def +/uni2AB7 4530 def +/uni2AB8 4531 def +/uni2AB9 4532 def +/uni2ABA 4533 def +/uni2AF9 4534 def +/uni2AFA 4535 def +/uni2B00 4536 def +/uni2B01 4537 def +/uni2B02 4538 def +/uni2B03 4539 def +/uni2B04 4540 def +/uni2B05 4541 def +/uni2B06 4542 def +/uni2B07 4543 def +/uni2B08 4544 def +/uni2B09 4545 def +/uni2B0A 4546 def +/uni2B0B 4547 def +/uni2B0C 4548 def +/uni2B0D 4549 def +/uni2B0E 4550 def +/uni2B0F 4551 def +/uni2B10 4552 def +/uni2B11 4553 def +/uni2B12 4554 def +/uni2B13 4555 def +/uni2B14 4556 def +/uni2B15 4557 def +/uni2B16 4558 def +/uni2B17 4559 def +/uni2B18 4560 def +/uni2B19 4561 def +/uni2B1A 4562 def +/uni2B1F 4563 def +/uni2B20 4564 def +/uni2B21 4565 def +/uni2B22 4566 def +/uni2B23 4567 def +/uni2B24 4568 def +/uni2B53 4569 def +/uni2B54 4570 def +/uni2C60 4571 def +/uni2C61 4572 def +/uni2C62 4573 def +/uni2C63 4574 def +/uni2C64 4575 def +/uni2C65 4576 def +/uni2C66 4577 def +/uni2C67 4578 def +/uni2C68 4579 def +/uni2C69 4580 def +/uni2C6A 4581 def +/uni2C6B 4582 def +/uni2C6C 4583 def +/uni2C6D 4584 def +/uni2C6E 4585 def +/uni2C6F 4586 def +/uni2C70 4587 def +/uni2C71 4588 def +/uni2C72 4589 def +/uni2C73 4590 def +/uni2C74 4591 def +/uni2C75 4592 def +/uni2C76 4593 def +/uni2C77 4594 def +/uni2C79 4595 def +/uni2C7A 4596 def +/uni2C7B 4597 def +/uni2C7C 4598 def +/uni2C7D 4599 def +/uni2C7E 4600 def +/uni2C7F 4601 def +/uni2D00 4602 def +/uni2D01 4603 def +/uni2D02 4604 def +/uni2D03 4605 def +/uni2D04 4606 def +/uni2D05 4607 def +/uni2D06 4608 def +/uni2D07 4609 def +/uni2D08 4610 def +/uni2D09 4611 def +/uni2D0A 4612 def +/uni2D0B 4613 def +/uni2D0C 4614 def +/uni2D0D 4615 def +/uni2D0E 4616 def +/uni2D0F 4617 def +/uni2D10 4618 def +/uni2D11 4619 def +/uni2D12 4620 def +/uni2D13 4621 def +/uni2D14 4622 def +/uni2D15 4623 def +/uni2D16 4624 def +/uni2D17 4625 def +/uni2D18 4626 def +/uni2D19 4627 def +/uni2D1A 4628 def +/uni2D1B 4629 def +/uni2D1C 4630 def +/uni2D1D 4631 def +/uni2D1E 4632 def +/uni2D1F 4633 def +/uni2D20 4634 def +/uni2D21 4635 def +/uni2D22 4636 def +/uni2D23 4637 def +/uni2D24 4638 def +/uni2D25 4639 def +/uni2D30 4640 def +/uni2D31 4641 def +/uni2D32 4642 def +/uni2D33 4643 def +/uni2D34 4644 def +/uni2D35 4645 def +/uni2D36 4646 def +/uni2D37 4647 def +/uni2D38 4648 def +/uni2D39 4649 def +/uni2D3A 4650 def +/uni2D3B 4651 def +/uni2D3C 4652 def +/uni2D3D 4653 def +/uni2D3E 4654 def +/uni2D3F 4655 def +/uni2D40 4656 def +/uni2D41 4657 def +/uni2D42 4658 def +/uni2D43 4659 def +/uni2D44 4660 def +/uni2D45 4661 def +/uni2D46 4662 def +/uni2D47 4663 def +/uni2D48 4664 def +/uni2D49 4665 def +/uni2D4A 4666 def +/uni2D4B 4667 def +/uni2D4C 4668 def +/uni2D4D 4669 def +/uni2D4E 4670 def +/uni2D4F 4671 def +/uni2D50 4672 def +/uni2D51 4673 def +/uni2D52 4674 def +/uni2D53 4675 def +/uni2D54 4676 def +/uni2D55 4677 def +/uni2D56 4678 def +/uni2D57 4679 def +/uni2D58 4680 def +/uni2D59 4681 def +/uni2D5A 4682 def +/uni2D5B 4683 def +/uni2D5C 4684 def +/uni2D5D 4685 def +/uni2D5E 4686 def +/uni2D5F 4687 def +/uni2D60 4688 def +/uni2D61 4689 def +/uni2D62 4690 def +/uni2D63 4691 def +/uni2D64 4692 def +/uni2D65 4693 def +/uni2D6F 4694 def +/uni2E18 4695 def +/uni2E1F 4696 def +/uni2E22 4697 def +/uni2E23 4698 def +/uni2E24 4699 def +/uni2E25 4700 def +/uni2E2E 4701 def +/uni4DC0 4702 def +/uni4DC1 4703 def +/uni4DC2 4704 def +/uni4DC3 4705 def +/uni4DC4 4706 def +/uni4DC5 4707 def +/uni4DC6 4708 def +/uni4DC7 4709 def +/uni4DC8 4710 def +/uni4DC9 4711 def +/uni4DCA 4712 def +/uni4DCB 4713 def +/uni4DCC 4714 def +/uni4DCD 4715 def +/uni4DCE 4716 def +/uni4DCF 4717 def +/uni4DD0 4718 def +/uni4DD1 4719 def +/uni4DD2 4720 def +/uni4DD3 4721 def +/uni4DD4 4722 def +/uni4DD5 4723 def +/uni4DD6 4724 def +/uni4DD7 4725 def +/uni4DD8 4726 def +/uni4DD9 4727 def +/uni4DDA 4728 def +/uni4DDB 4729 def +/uni4DDC 4730 def +/uni4DDD 4731 def +/uni4DDE 4732 def +/uni4DDF 4733 def +/uni4DE0 4734 def +/uni4DE1 4735 def +/uni4DE2 4736 def +/uni4DE3 4737 def +/uni4DE4 4738 def +/uni4DE5 4739 def +/uni4DE6 4740 def +/uni4DE7 4741 def +/uni4DE8 4742 def +/uni4DE9 4743 def +/uni4DEA 4744 def +/uni4DEB 4745 def +/uni4DEC 4746 def +/uni4DED 4747 def +/uni4DEE 4748 def +/uni4DEF 4749 def +/uni4DF0 4750 def +/uni4DF1 4751 def +/uni4DF2 4752 def +/uni4DF3 4753 def +/uni4DF4 4754 def +/uni4DF5 4755 def +/uni4DF6 4756 def +/uni4DF7 4757 def +/uni4DF8 4758 def +/uni4DF9 4759 def +/uni4DFA 4760 def +/uni4DFB 4761 def +/uni4DFC 4762 def +/uni4DFD 4763 def +/uni4DFE 4764 def +/uni4DFF 4765 def +/uniA4D0 4766 def +/uniA4D1 4767 def +/uniA4D2 4768 def +/uniA4D3 4769 def +/uniA4D4 4770 def +/uniA4D5 4771 def +/uniA4D6 4772 def +/uniA4D7 4773 def +/uniA4D8 4774 def +/uniA4D9 4775 def +/uniA4DA 4776 def +/uniA4DB 4777 def +/uniA4DC 4778 def +/uniA4DD 4779 def +/uniA4DE 4780 def +/uniA4DF 4781 def +/uniA4E0 4782 def +/uniA4E1 4783 def +/uniA4E2 4784 def +/uniA4E3 4785 def +/uniA4E4 4786 def +/uniA4E5 4787 def +/uniA4E6 4788 def +/uniA4E7 4789 def +/uniA4E8 4790 def +/uniA4E9 4791 def +/uniA4EA 4792 def +/uniA4EB 4793 def +/uniA4EC 4794 def +/uniA4ED 4795 def +/uniA4EE 4796 def +/uniA4EF 4797 def +/uniA4F0 4798 def +/uniA4F1 4799 def +/uniA4F2 4800 def +/uniA4F3 4801 def +/uniA4F4 4802 def +/uniA4F5 4803 def +/uniA4F6 4804 def +/uniA4F7 4805 def +/uniA4F8 4806 def +/uniA4F9 4807 def +/uniA4FA 4808 def +/uniA4FB 4809 def +/uniA4FC 4810 def +/uniA4FD 4811 def +/uniA4FE 4812 def +/uniA4FF 4813 def +/uniA644 4814 def +/uniA645 4815 def +/uniA646 4816 def +/uniA647 4817 def +/uniA64C 4818 def +/uniA64D 4819 def +/uniA650 4820 def +/uniA651 4821 def +/uniA654 4822 def +/uniA655 4823 def +/uniA656 4824 def +/uniA657 4825 def +/uniA662 4826 def +/uniA663 4827 def +/uniA664 4828 def +/uniA665 4829 def +/uniA666 4830 def +/uniA667 4831 def +/uniA668 4832 def +/uniA669 4833 def +/uniA66A 4834 def +/uniA66B 4835 def +/uniA66C 4836 def +/uniA66D 4837 def +/uniA66E 4838 def +/uniA68A 4839 def +/uniA68B 4840 def +/uniA68C 4841 def +/uniA68D 4842 def +/uniA694 4843 def +/uniA695 4844 def +/uniA708 4845 def +/uniA709 4846 def +/uniA70A 4847 def +/uniA70B 4848 def +/uniA70C 4849 def +/uniA70D 4850 def +/uniA70E 4851 def +/uniA70F 4852 def +/uniA710 4853 def +/uniA711 4854 def +/uniA712 4855 def +/uniA713 4856 def +/uniA714 4857 def +/uniA715 4858 def +/uniA716 4859 def +/uniA71B 4860 def +/uniA71C 4861 def +/uniA71D 4862 def +/uniA71E 4863 def +/uniA71F 4864 def +/uniA722 4865 def +/uniA723 4866 def +/uniA724 4867 def +/uniA725 4868 def +/uniA726 4869 def +/uniA727 4870 def +/uniA728 4871 def +/uniA729 4872 def +/uniA72A 4873 def +/uniA72B 4874 def +/uniA730 4875 def +/uniA731 4876 def +/uniA732 4877 def +/uniA733 4878 def +/uniA734 4879 def +/uniA735 4880 def +/uniA736 4881 def +/uniA737 4882 def +/uniA738 4883 def +/uniA739 4884 def +/uniA73A 4885 def +/uniA73B 4886 def +/uniA73C 4887 def +/uniA73D 4888 def +/uniA73E 4889 def +/uniA73F 4890 def +/uniA740 4891 def +/uniA741 4892 def +/uniA746 4893 def +/uniA747 4894 def +/uniA748 4895 def +/uniA749 4896 def +/uniA74A 4897 def +/uniA74B 4898 def +/uniA74E 4899 def +/uniA74F 4900 def +/uniA750 4901 def +/uniA751 4902 def +/uniA752 4903 def +/uniA753 4904 def +/uniA756 4905 def +/uniA757 4906 def +/uniA764 4907 def +/uniA765 4908 def +/uniA766 4909 def +/uniA767 4910 def +/uniA780 4911 def +/uniA781 4912 def +/uniA782 4913 def +/uniA783 4914 def +/uniA789 4915 def +/uniA78A 4916 def +/uniA78B 4917 def +/uniA78C 4918 def +/uniA78D 4919 def +/uniA78E 4920 def +/uniA790 4921 def +/uniA791 4922 def +/uniA7A0 4923 def +/uniA7A1 4924 def +/uniA7A2 4925 def +/uniA7A3 4926 def +/uniA7A4 4927 def +/uniA7A5 4928 def +/uniA7A6 4929 def +/uniA7A7 4930 def +/uniA7A8 4931 def +/uniA7A9 4932 def +/uniA7AA 4933 def +/uniA7F8 4934 def +/uniA7F9 4935 def +/uniA7FA 4936 def +/uniA7FB 4937 def +/uniA7FC 4938 def +/uniA7FD 4939 def +/uniA7FE 4940 def +/uniA7FF 4941 def +/uni02E5.5 4942 def +/uni02E6.5 4943 def +/uni02E7.5 4944 def +/uni02E8.5 4945 def +/uni02E9.5 4946 def +/uni02E5.4 4947 def +/uni02E6.4 4948 def +/uni02E7.4 4949 def +/uni02E8.4 4950 def +/uni02E9.4 4951 def +/uni02E5.3 4952 def +/uni02E6.3 4953 def +/uni02E7.3 4954 def +/uni02E8.3 4955 def +/uni02E9.3 4956 def +/uni02E5.2 4957 def +/uni02E6.2 4958 def +/uni02E7.2 4959 def +/uni02E8.2 4960 def +/uni02E9.2 4961 def +/uni02E5.1 4962 def +/uni02E6.1 4963 def +/uni02E7.1 4964 def +/uni02E8.1 4965 def +/uni02E9.1 4966 def +/stem 4967 def +/uniF000 4968 def +/uniF001 4969 def +/uniF002 4970 def +/uniF003 4971 def +/uniF400 4972 def +/uniF401 4973 def +/uniF402 4974 def +/uniF403 4975 def +/uniF404 4976 def +/uniF405 4977 def +/uniF406 4978 def +/uniF407 4979 def +/uniF408 4980 def +/uniF409 4981 def +/uniF40A 4982 def +/uniF40B 4983 def +/uniF40C 4984 def +/uniF40D 4985 def +/uniF40E 4986 def +/uniF40F 4987 def +/uniF410 4988 def +/uniF411 4989 def +/uniF412 4990 def +/uniF413 4991 def +/uniF414 4992 def +/uniF415 4993 def +/uniF416 4994 def +/uniF417 4995 def +/uniF418 4996 def +/uniF419 4997 def +/uniF41A 4998 def +/uniF41B 4999 def +/uniF41C 5000 def +/uniF41D 5001 def +/uniF41E 5002 def +/uniF41F 5003 def +/uniF420 5004 def +/uniF421 5005 def +/uniF422 5006 def +/uniF423 5007 def +/uniF424 5008 def +/uniF425 5009 def +/uniF426 5010 def +/uniF428 5011 def +/uniF429 5012 def +/uniF42A 5013 def +/uniF42B 5014 def +/uniF42C 5015 def +/uniF42D 5016 def +/uniF42E 5017 def +/uniF42F 5018 def +/uniF430 5019 def +/uniF431 5020 def +/uniF432 5021 def +/uniF433 5022 def +/uniF434 5023 def +/uniF435 5024 def +/uniF436 5025 def +/uniF437 5026 def +/uniF438 5027 def +/uniF439 5028 def +/uniF43A 5029 def +/uniF43B 5030 def +/uniF43C 5031 def +/uniF43D 5032 def +/uniF43E 5033 def +/uniF43F 5034 def +/uniF440 5035 def +/uniF441 5036 def +/uniF6C5 5037 def +/uniFB00 5038 def +/fi 5039 def +/fl 5040 def +/uniFB03 5041 def +/uniFB04 5042 def +/uniFB05 5043 def +/uniFB06 5044 def +/uniFB13 5045 def +/uniFB14 5046 def +/uniFB15 5047 def +/uniFB16 5048 def +/uniFB17 5049 def +/uniFB1D 5050 def +/uniFB1E 5051 def +/uniFB1F 5052 def +/uniFB20 5053 def +/uniFB21 5054 def +/uniFB22 5055 def +/uniFB23 5056 def +/uniFB24 5057 def +/uniFB25 5058 def +/uniFB26 5059 def +/uniFB27 5060 def +/uniFB28 5061 def +/uniFB29 5062 def +/uniFB2A 5063 def +/uniFB2B 5064 def +/uniFB2C 5065 def +/uniFB2D 5066 def +/uniFB2E 5067 def +/uniFB2F 5068 def +/uniFB30 5069 def +/uniFB31 5070 def +/uniFB32 5071 def +/uniFB33 5072 def +/uniFB34 5073 def +/uniFB35 5074 def +/uniFB36 5075 def +/uniFB38 5076 def +/uniFB39 5077 def +/uniFB3A 5078 def +/uniFB3B 5079 def +/uniFB3C 5080 def +/uniFB3E 5081 def +/uniFB40 5082 def +/uniFB41 5083 def +/uniFB43 5084 def +/uniFB44 5085 def +/uniFB46 5086 def +/uniFB47 5087 def +/uniFB48 5088 def +/uniFB49 5089 def +/uniFB4A 5090 def +/uniFB4B 5091 def +/uniFB4C 5092 def +/uniFB4D 5093 def +/uniFB4E 5094 def +/uniFB4F 5095 def +/uniFB52 5096 def +/uniFB53 5097 def +/uniFB54 5098 def +/uniFB55 5099 def +/uniFB56 5100 def +/uniFB57 5101 def +/uniFB58 5102 def +/uniFB59 5103 def +/uniFB5A 5104 def +/uniFB5B 5105 def +/uniFB5C 5106 def +/uniFB5D 5107 def +/uniFB5E 5108 def +/uniFB5F 5109 def +/uniFB60 5110 def +/uniFB61 5111 def +/uniFB62 5112 def +/uniFB63 5113 def +/uniFB64 5114 def +/uniFB65 5115 def +/uniFB66 5116 def +/uniFB67 5117 def +/uniFB68 5118 def +/uniFB69 5119 def +/uniFB6A 5120 def +/uniFB6B 5121 def +/uniFB6C 5122 def +/uniFB6D 5123 def +/uniFB6E 5124 def +/uniFB6F 5125 def +/uniFB70 5126 def +/uniFB71 5127 def +/uniFB72 5128 def +/uniFB73 5129 def +/uniFB74 5130 def +/uniFB75 5131 def +/uniFB76 5132 def +/uniFB77 5133 def +/uniFB78 5134 def +/uniFB79 5135 def +/uniFB7A 5136 def +/uniFB7B 5137 def +/uniFB7C 5138 def +/uniFB7D 5139 def +/uniFB7E 5140 def +/uniFB7F 5141 def +/uniFB80 5142 def +/uniFB81 5143 def +/uniFB82 5144 def +/uniFB83 5145 def +/uniFB84 5146 def +/uniFB85 5147 def +/uniFB86 5148 def +/uniFB87 5149 def +/uniFB88 5150 def +/uniFB89 5151 def +/uniFB8A 5152 def +/uniFB8B 5153 def +/uniFB8C 5154 def +/uniFB8D 5155 def +/uniFB8E 5156 def +/uniFB8F 5157 def +/uniFB90 5158 def +/uniFB91 5159 def +/uniFB92 5160 def +/uniFB93 5161 def +/uniFB94 5162 def +/uniFB95 5163 def +/uniFB96 5164 def +/uniFB97 5165 def +/uniFB98 5166 def +/uniFB99 5167 def +/uniFB9A 5168 def +/uniFB9B 5169 def +/uniFB9C 5170 def +/uniFB9D 5171 def +/uniFB9E 5172 def +/uniFB9F 5173 def +/uniFBA0 5174 def +/uniFBA1 5175 def +/uniFBA2 5176 def +/uniFBA3 5177 def +/uniFBAA 5178 def +/uniFBAB 5179 def +/uniFBAC 5180 def +/uniFBAD 5181 def +/uniFBD3 5182 def +/uniFBD4 5183 def +/uniFBD5 5184 def +/uniFBD6 5185 def +/uniFBD7 5186 def +/uniFBD8 5187 def +/uniFBD9 5188 def +/uniFBDA 5189 def +/uniFBDB 5190 def +/uniFBDC 5191 def +/uniFBDE 5192 def +/uniFBDF 5193 def +/uniFBE4 5194 def +/uniFBE5 5195 def +/uniFBE6 5196 def +/uniFBE7 5197 def +/uniFBE8 5198 def +/uniFBE9 5199 def +/uniFBFC 5200 def +/uniFBFD 5201 def +/uniFBFE 5202 def +/uniFBFF 5203 def +/uniFE00 5204 def +/uniFE01 5205 def +/uniFE02 5206 def +/uniFE03 5207 def +/uniFE04 5208 def +/uniFE05 5209 def +/uniFE06 5210 def +/uniFE07 5211 def +/uniFE08 5212 def +/uniFE09 5213 def +/uniFE0A 5214 def +/uniFE0B 5215 def +/uniFE0C 5216 def +/uniFE0D 5217 def +/uniFE0E 5218 def +/uniFE0F 5219 def +/uniFE20 5220 def +/uniFE21 5221 def +/uniFE22 5222 def +/uniFE23 5223 def +/uniFE70 5224 def +/uniFE71 5225 def +/uniFE72 5226 def +/uniFE73 5227 def +/uniFE74 5228 def +/uniFE76 5229 def +/uniFE77 5230 def +/uniFE78 5231 def +/uniFE79 5232 def +/uniFE7A 5233 def +/uniFE7B 5234 def +/uniFE7C 5235 def +/uniFE7D 5236 def +/uniFE7E 5237 def +/uniFE7F 5238 def +/uniFE80 5239 def +/uniFE81 5240 def +/uniFE82 5241 def +/uniFE83 5242 def +/uniFE84 5243 def +/uniFE85 5244 def +/uniFE86 5245 def +/uniFE87 5246 def +/uniFE88 5247 def +/uniFE89 5248 def +/uniFE8A 5249 def +/uniFE8B 5250 def +/uniFE8C 5251 def +/uniFE8D 5252 def +/uniFE8E 5253 def +/uniFE8F 5254 def +/uniFE90 5255 def +/uniFE91 5256 def +/uniFE92 5257 def +/uniFE93 5258 def +/uniFE94 5259 def +/uniFE95 5260 def +/uniFE96 5261 def +/uniFE97 5262 def +/uniFE98 5263 def +/uniFE99 5264 def +/uniFE9A 5265 def +/uniFE9B 5266 def +/uniFE9C 5267 def +/uniFE9D 5268 def +/uniFE9E 5269 def +/uniFE9F 5270 def +/uniFEA0 5271 def +/uniFEA1 5272 def +/uniFEA2 5273 def +/uniFEA3 5274 def +/uniFEA4 5275 def +/uniFEA5 5276 def +/uniFEA6 5277 def +/uniFEA7 5278 def +/uniFEA8 5279 def +/uniFEA9 5280 def +/uniFEAA 5281 def +/uniFEAB 5282 def +/uniFEAC 5283 def +/uniFEAD 5284 def +/uniFEAE 5285 def +/uniFEAF 5286 def +/uniFEB0 5287 def +/uniFEB1 5288 def +/uniFEB2 5289 def +/uniFEB3 5290 def +/uniFEB4 5291 def +/uniFEB5 5292 def +/uniFEB6 5293 def +/uniFEB7 5294 def +/uniFEB8 5295 def +/uniFEB9 5296 def +/uniFEBA 5297 def +/uniFEBB 5298 def +/uniFEBC 5299 def +/uniFEBD 5300 def +/uniFEBE 5301 def +/uniFEBF 5302 def +/uniFEC0 5303 def +/uniFEC1 5304 def +/uniFEC2 5305 def +/uniFEC3 5306 def +/uniFEC4 5307 def +/uniFEC5 5308 def +/uniFEC6 5309 def +/uniFEC7 5310 def +/uniFEC8 5311 def +/uniFEC9 5312 def +/uniFECA 5313 def +/uniFECB 5314 def +/uniFECC 5315 def +/uniFECD 5316 def +/uniFECE 5317 def +/uniFECF 5318 def +/uniFED0 5319 def +/uniFED1 5320 def +/uniFED2 5321 def +/uniFED3 5322 def +/uniFED4 5323 def +/uniFED5 5324 def +/uniFED6 5325 def +/uniFED7 5326 def +/uniFED8 5327 def +/uniFED9 5328 def +/uniFEDA 5329 def +/uniFEDB 5330 def +/uniFEDC 5331 def +/uniFEDD 5332 def +/uniFEDE 5333 def +/uniFEDF 5334 def +/uniFEE0 5335 def +/uniFEE1 5336 def +/uniFEE2 5337 def +/uniFEE3 5338 def +/uniFEE4 5339 def +/uniFEE5 5340 def +/uniFEE6 5341 def +/uniFEE7 5342 def +/uniFEE8 5343 def +/uniFEE9 5344 def +/uniFEEA 5345 def +/uniFEEB 5346 def +/uniFEEC 5347 def +/uniFEED 5348 def +/uniFEEE 5349 def +/uniFEEF 5350 def +/uniFEF0 5351 def +/uniFEF1 5352 def +/uniFEF2 5353 def +/uniFEF3 5354 def +/uniFEF4 5355 def +/uniFEF5 5356 def +/uniFEF6 5357 def +/uniFEF7 5358 def +/uniFEF8 5359 def +/uniFEF9 5360 def +/uniFEFA 5361 def +/uniFEFB 5362 def +/uniFEFC 5363 def +/uniFEFF 5364 def +/uniFFF9 5365 def +/uniFFFA 5366 def +/uniFFFB 5367 def +/uniFFFC 5368 def +/uniFFFD 5369 def +/u10300 5370 def +/u10301 5371 def +/u10302 5372 def +/u10303 5373 def +/u10304 5374 def +/u10305 5375 def +/u10306 5376 def +/u10307 5377 def +/u10308 5378 def +/u10309 5379 def +/u1030A 5380 def +/u1030B 5381 def +/u1030C 5382 def +/u1030D 5383 def +/u1030E 5384 def +/u1030F 5385 def +/u10310 5386 def +/u10311 5387 def +/u10312 5388 def +/u10313 5389 def +/u10314 5390 def +/u10315 5391 def +/u10316 5392 def +/u10317 5393 def +/u10318 5394 def +/u10319 5395 def +/u1031A 5396 def +/u1031B 5397 def +/u1031C 5398 def +/u1031D 5399 def +/u1031E 5400 def +/u10320 5401 def +/u10321 5402 def +/u10322 5403 def +/u10323 5404 def +/u1D300 5405 def +/u1D301 5406 def +/u1D302 5407 def +/u1D303 5408 def +/u1D304 5409 def +/u1D305 5410 def +/u1D306 5411 def +/u1D307 5412 def +/u1D308 5413 def +/u1D309 5414 def +/u1D30A 5415 def +/u1D30B 5416 def +/u1D30C 5417 def +/u1D30D 5418 def +/u1D30E 5419 def +/u1D30F 5420 def +/u1D310 5421 def +/u1D311 5422 def +/u1D312 5423 def +/u1D313 5424 def +/u1D314 5425 def +/u1D315 5426 def +/u1D316 5427 def +/u1D317 5428 def +/u1D318 5429 def +/u1D319 5430 def +/u1D31A 5431 def +/u1D31B 5432 def +/u1D31C 5433 def +/u1D31D 5434 def +/u1D31E 5435 def +/u1D31F 5436 def +/u1D320 5437 def +/u1D321 5438 def +/u1D322 5439 def +/u1D323 5440 def +/u1D324 5441 def +/u1D325 5442 def +/u1D326 5443 def +/u1D327 5444 def +/u1D328 5445 def +/u1D329 5446 def +/u1D32A 5447 def +/u1D32B 5448 def +/u1D32C 5449 def +/u1D32D 5450 def +/u1D32E 5451 def +/u1D32F 5452 def +/u1D330 5453 def +/u1D331 5454 def +/u1D332 5455 def +/u1D333 5456 def +/u1D334 5457 def +/u1D335 5458 def +/u1D336 5459 def +/u1D337 5460 def +/u1D338 5461 def +/u1D339 5462 def +/u1D33A 5463 def +/u1D33B 5464 def +/u1D33C 5465 def +/u1D33D 5466 def +/u1D33E 5467 def +/u1D33F 5468 def +/u1D340 5469 def +/u1D341 5470 def +/u1D342 5471 def +/u1D343 5472 def +/u1D344 5473 def +/u1D345 5474 def +/u1D346 5475 def +/u1D347 5476 def +/u1D348 5477 def +/u1D349 5478 def +/u1D34A 5479 def +/u1D34B 5480 def +/u1D34C 5481 def +/u1D34D 5482 def +/u1D34E 5483 def +/u1D34F 5484 def +/u1D350 5485 def +/u1D351 5486 def +/u1D352 5487 def +/u1D353 5488 def +/u1D354 5489 def +/u1D355 5490 def +/u1D356 5491 def +/u1D538 5492 def +/u1D539 5493 def +/u1D53B 5494 def +/u1D53C 5495 def +/u1D53D 5496 def +/u1D53E 5497 def +/u1D540 5498 def +/u1D541 5499 def +/u1D542 5500 def +/u1D543 5501 def +/u1D544 5502 def +/u1D546 5503 def +/u1D54A 5504 def +/u1D54B 5505 def +/u1D54C 5506 def +/u1D54D 5507 def +/u1D54E 5508 def +/u1D54F 5509 def +/u1D550 5510 def +/u1D552 5511 def +/u1D553 5512 def +/u1D554 5513 def +/u1D555 5514 def +/u1D556 5515 def +/u1D557 5516 def +/u1D558 5517 def +/u1D559 5518 def +/u1D55A 5519 def +/u1D55B 5520 def +/u1D55C 5521 def +/u1D55D 5522 def +/u1D55E 5523 def +/u1D55F 5524 def +/u1D560 5525 def +/u1D561 5526 def +/u1D562 5527 def +/u1D563 5528 def +/u1D564 5529 def +/u1D565 5530 def +/u1D566 5531 def +/u1D567 5532 def +/u1D568 5533 def +/u1D569 5534 def +/u1D56A 5535 def +/u1D56B 5536 def +/u1D5A0 5537 def +/u1D5A1 5538 def +/u1D5A2 5539 def +/u1D5A3 5540 def +/u1D5A4 5541 def +/u1D5A5 5542 def +/u1D5A6 5543 def +/u1D5A7 5544 def +/u1D5A8 5545 def +/u1D5A9 5546 def +/u1D5AA 5547 def +/u1D5AB 5548 def +/u1D5AC 5549 def +/u1D5AD 5550 def +/u1D5AE 5551 def +/u1D5AF 5552 def +/u1D5B0 5553 def +/u1D5B1 5554 def +/u1D5B2 5555 def +/u1D5B3 5556 def +/u1D5B4 5557 def +/u1D5B5 5558 def +/u1D5B6 5559 def +/u1D5B7 5560 def +/u1D5B8 5561 def +/u1D5B9 5562 def +/u1D5BA 5563 def +/u1D5BB 5564 def +/u1D5BC 5565 def +/u1D5BD 5566 def +/u1D5BE 5567 def +/u1D5BF 5568 def +/u1D5C0 5569 def +/u1D5C1 5570 def +/u1D5C2 5571 def +/u1D5C3 5572 def +/u1D5C4 5573 def +/u1D5C5 5574 def +/u1D5C6 5575 def +/u1D5C7 5576 def +/u1D5C8 5577 def +/u1D5C9 5578 def +/u1D5CA 5579 def +/u1D5CB 5580 def +/u1D5CC 5581 def +/u1D5CD 5582 def +/u1D5CE 5583 def +/u1D5CF 5584 def +/u1D5D0 5585 def +/u1D5D1 5586 def +/u1D5D2 5587 def +/u1D5D3 5588 def +/u1D7D8 5589 def +/u1D7D9 5590 def +/u1D7DA 5591 def +/u1D7DB 5592 def +/u1D7DC 5593 def +/u1D7DD 5594 def +/u1D7DE 5595 def +/u1D7DF 5596 def +/u1D7E0 5597 def +/u1D7E1 5598 def +/u1D7E2 5599 def +/u1D7E3 5600 def +/u1D7E4 5601 def +/u1D7E5 5602 def +/u1D7E6 5603 def +/u1D7E7 5604 def +/u1D7E8 5605 def +/u1D7E9 5606 def +/u1D7EA 5607 def +/u1D7EB 5608 def +/u1EE00 5609 def +/u1EE01 5610 def +/u1EE02 5611 def +/u1EE03 5612 def +/u1EE05 5613 def +/u1EE06 5614 def +/u1EE07 5615 def +/u1EE08 5616 def +/u1EE09 5617 def +/u1EE0A 5618 def +/u1EE0B 5619 def +/u1EE0C 5620 def +/u1EE0D 5621 def +/u1EE0E 5622 def +/u1EE0F 5623 def +/u1EE10 5624 def +/u1EE11 5625 def +/u1EE12 5626 def +/u1EE13 5627 def +/u1EE14 5628 def +/u1EE15 5629 def +/u1EE16 5630 def +/u1EE17 5631 def +/u1EE18 5632 def +/u1EE19 5633 def +/u1EE1A 5634 def +/u1EE1B 5635 def +/u1EE1C 5636 def +/u1EE1D 5637 def +/u1EE1E 5638 def +/u1EE1F 5639 def +/u1EE21 5640 def +/u1EE22 5641 def +/u1EE24 5642 def +/u1EE27 5643 def +/u1EE29 5644 def +/u1EE2A 5645 def +/u1EE2B 5646 def +/u1EE2C 5647 def +/u1EE2D 5648 def +/u1EE2E 5649 def +/u1EE2F 5650 def +/u1EE30 5651 def +/u1EE31 5652 def +/u1EE32 5653 def +/u1EE34 5654 def +/u1EE35 5655 def +/u1EE36 5656 def +/u1EE37 5657 def +/u1EE39 5658 def +/u1EE3B 5659 def +/u1EE61 5660 def +/u1EE62 5661 def +/u1EE64 5662 def +/u1EE67 5663 def +/u1EE68 5664 def +/u1EE69 5665 def +/u1EE6A 5666 def +/u1EE6C 5667 def +/u1EE6D 5668 def +/u1EE6E 5669 def +/u1EE6F 5670 def +/u1EE70 5671 def +/u1EE71 5672 def +/u1EE72 5673 def +/u1EE74 5674 def +/u1EE75 5675 def +/u1EE76 5676 def +/u1EE77 5677 def +/u1EE79 5678 def +/u1EE7A 5679 def +/u1EE7B 5680 def +/u1EE7C 5681 def +/u1EE7E 5682 def +/u1F030 5683 def +/u1F031 5684 def +/u1F032 5685 def +/u1F033 5686 def +/u1F034 5687 def +/u1F035 5688 def +/u1F036 5689 def +/u1F037 5690 def +/u1F038 5691 def +/u1F039 5692 def +/u1F03A 5693 def +/u1F03B 5694 def +/u1F03C 5695 def +/u1F03D 5696 def +/u1F03E 5697 def +/u1F03F 5698 def +/u1F040 5699 def +/u1F041 5700 def +/u1F042 5701 def +/u1F043 5702 def +/u1F044 5703 def +/u1F045 5704 def +/u1F046 5705 def +/u1F047 5706 def +/u1F048 5707 def +/u1F049 5708 def +/u1F04A 5709 def +/u1F04B 5710 def +/u1F04C 5711 def +/u1F04D 5712 def +/u1F04E 5713 def +/u1F04F 5714 def +/u1F050 5715 def +/u1F051 5716 def +/u1F052 5717 def +/u1F053 5718 def +/u1F054 5719 def +/u1F055 5720 def +/u1F056 5721 def +/u1F057 5722 def +/u1F058 5723 def +/u1F059 5724 def +/u1F05A 5725 def +/u1F05B 5726 def +/u1F05C 5727 def +/u1F05D 5728 def +/u1F05E 5729 def +/u1F05F 5730 def +/u1F060 5731 def +/u1F061 5732 def +/u1F062 5733 def +/u1F063 5734 def +/u1F064 5735 def +/u1F065 5736 def +/u1F066 5737 def +/u1F067 5738 def +/u1F068 5739 def +/u1F069 5740 def +/u1F06A 5741 def +/u1F06B 5742 def +/u1F06C 5743 def +/u1F06D 5744 def +/u1F06E 5745 def +/u1F06F 5746 def +/u1F070 5747 def +/u1F071 5748 def +/u1F072 5749 def +/u1F073 5750 def +/u1F074 5751 def +/u1F075 5752 def +/u1F076 5753 def +/u1F077 5754 def +/u1F078 5755 def +/u1F079 5756 def +/u1F07A 5757 def +/u1F07B 5758 def +/u1F07C 5759 def +/u1F07D 5760 def +/u1F07E 5761 def +/u1F07F 5762 def +/u1F080 5763 def +/u1F081 5764 def +/u1F082 5765 def +/u1F083 5766 def +/u1F084 5767 def +/u1F085 5768 def +/u1F086 5769 def +/u1F087 5770 def +/u1F088 5771 def +/u1F089 5772 def +/u1F08A 5773 def +/u1F08B 5774 def +/u1F08C 5775 def +/u1F08D 5776 def +/u1F08E 5777 def +/u1F08F 5778 def +/u1F090 5779 def +/u1F091 5780 def +/u1F092 5781 def +/u1F093 5782 def +/u1F0A0 5783 def +/u1F0A1 5784 def +/u1F0A2 5785 def +/u1F0A3 5786 def +/u1F0A4 5787 def +/u1F0A5 5788 def +/u1F0A6 5789 def +/u1F0A7 5790 def +/u1F0A8 5791 def +/u1F0A9 5792 def +/u1F0AA 5793 def +/u1F0AB 5794 def +/u1F0AC 5795 def +/u1F0AD 5796 def +/u1F0AE 5797 def +/u1F0B1 5798 def +/u1F0B2 5799 def +/u1F0B3 5800 def +/u1F0B4 5801 def +/u1F0B5 5802 def +/u1F0B6 5803 def +/u1F0B7 5804 def +/u1F0B8 5805 def +/u1F0B9 5806 def +/u1F0BA 5807 def +/u1F0BB 5808 def +/u1F0BC 5809 def +/u1F0BD 5810 def +/u1F0BE 5811 def +/u1F0C1 5812 def +/u1F0C2 5813 def +/u1F0C3 5814 def +/u1F0C4 5815 def +/u1F0C5 5816 def +/u1F0C6 5817 def +/u1F0C7 5818 def +/u1F0C8 5819 def +/u1F0C9 5820 def +/u1F0CA 5821 def +/u1F0CB 5822 def +/u1F0CC 5823 def +/u1F0CD 5824 def +/u1F0CE 5825 def +/u1F0CF 5826 def +/u1F0D1 5827 def +/u1F0D2 5828 def +/u1F0D3 5829 def +/u1F0D4 5830 def +/u1F0D5 5831 def +/u1F0D6 5832 def +/u1F0D7 5833 def +/u1F0D8 5834 def +/u1F0D9 5835 def +/u1F0DA 5836 def +/u1F0DB 5837 def +/u1F0DC 5838 def +/u1F0DD 5839 def +/u1F0DE 5840 def +/u1F0DF 5841 def +/u1F42D 5842 def +/u1F42E 5843 def +/u1F431 5844 def +/u1F435 5845 def +/u1F600 5846 def +/u1F601 5847 def +/u1F602 5848 def +/u1F603 5849 def +/u1F604 5850 def +/u1F605 5851 def +/u1F606 5852 def +/u1F607 5853 def +/u1F608 5854 def +/u1F609 5855 def +/u1F60A 5856 def +/u1F60B 5857 def +/u1F60C 5858 def +/u1F60D 5859 def +/u1F60E 5860 def +/u1F60F 5861 def +/u1F610 5862 def +/u1F611 5863 def +/u1F612 5864 def +/u1F613 5865 def +/u1F614 5866 def +/u1F615 5867 def +/u1F616 5868 def +/u1F617 5869 def +/u1F618 5870 def +/u1F619 5871 def +/u1F61A 5872 def +/u1F61B 5873 def +/u1F61C 5874 def +/u1F61D 5875 def +/u1F61E 5876 def +/u1F61F 5877 def +/u1F620 5878 def +/u1F621 5879 def +/u1F622 5880 def +/u1F623 5881 def +/u1F625 5882 def +/u1F626 5883 def +/u1F627 5884 def +/u1F628 5885 def +/u1F629 5886 def +/u1F62A 5887 def +/u1F62B 5888 def +/u1F62D 5889 def +/u1F62E 5890 def +/u1F62F 5891 def +/u1F630 5892 def +/u1F631 5893 def +/u1F632 5894 def +/u1F633 5895 def +/u1F634 5896 def +/u1F635 5897 def +/u1F636 5898 def +/u1F637 5899 def +/u1F638 5900 def +/u1F639 5901 def +/u1F63A 5902 def +/u1F63B 5903 def +/u1F63C 5904 def +/u1F63D 5905 def +/u1F63E 5906 def +/u1F63F 5907 def +/u1F640 5908 def +/dlLtcaron 5909 def +/Dieresis 5910 def +/Acute 5911 def +/Tilde 5912 def +/Grave 5913 def +/Circumflex 5914 def +/Caron 5915 def +/uni0311.case 5916 def +/Breve 5917 def +/Dotaccent 5918 def +/Hungarumlaut 5919 def +/Doublegrave 5920 def +/arabic_dot 5921 def +/arabic_2dots 5922 def +/arabic_3dots 5923 def +/arabic_3dots_a 5924 def +/arabic_2dots_a 5925 def +/arabic_4dots 5926 def +/uni066E.fina 5927 def +/uni066E.init 5928 def +/uni066E.medi 5929 def +/uni06A1.fina 5930 def +/uni06A1.init 5931 def +/uni06A1.medi 5932 def +/uni066F.fina 5933 def +/uni066F.init 5934 def +/uni066F.medi 5935 def +/uni06BA.init 5936 def +/uni06BA.medi 5937 def +/arabic_ring 5938 def +/uni067C.fina 5939 def +/uni067C.init 5940 def +/uni067C.medi 5941 def +/uni067D.fina 5942 def +/uni067D.init 5943 def +/uni067D.medi 5944 def +/uni0681.fina 5945 def +/uni0681.init 5946 def +/uni0681.medi 5947 def +/uni0682.fina 5948 def +/uni0682.init 5949 def +/uni0682.medi 5950 def +/uni0685.fina 5951 def +/uni0685.init 5952 def +/uni0685.medi 5953 def +/uni06BF.fina 5954 def +/uni06BF.init 5955 def +/uni06BF.medi 5956 def +/arabic_gaf_bar 5957 def +/Eng.alt 5958 def +/uni0268.dotless 5959 def +/uni029D.dotless 5960 def +/uni03080304 5961 def +/uni03040308 5962 def +/uni03070304 5963 def +/uni03080301 5964 def +/uni03080300 5965 def +/uni03040301 5966 def +/uni03040300 5967 def +/uni03030304 5968 def +/uni0308030C 5969 def +end readonly def + /sfnts[<00010000001201000004002047444546196b17d40000012c0000002247504f53b6adcb8e0000015000000ec44753 +5542871f76f900001014000000e84d415448093f3384000010fc000000f64f532f326aab715a000011f400000056636d6170 +009e06b10000124c000000586376742000691d39000012a4000001fe6670676d7134766a000014a4000000ab676173700007 +0007000015500000000c676c79669ab7aa750000155c0000a37c68656164085dc2860000b8d800000036686865610d9f1ebe +0000b91000000024686d74781390a0b70000b93400005d466c6f6361900268200001167c00002ea66d6178701bbf06710001 +4524000000206e616d6527ed3dbc00014544000001d4706f73745e83c6f9000147180000e1b3707265703b07f100000228cc +0000056800010000000c00000000000000020003000300030001008702110001174617460001000000010000000a002e003c +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 +000000000000000000000000000000000000000000000000000000000001003300880089009200940095009600970098009b +009c009d009e009f00a000a100aa00ab00ac00ad00b200b300b400b500b600b700b800bf00c100c200c400c600c800ce00d0 +00d200dd00e000fb00ff0102010a01160117011a011b0120012201260130013a013f0002002300880088000e00890089000f +009400980003009b009e0006009f009f000700a000a0001000a100a1001100aa00ad000900b200b2001200b300b3000a00b4 +00b8000b00bf00bf000d00c100c1000d00c200c2001300c400c4001300c600c6001400c800c8000f00ce00ce000f00d200d2 +001500dd00dd000900e000e0000100fb00fb000200ff00ff0002010201020016010a010a000a01160116000401170117000c +011a011a0004011b011b0017012001200005012201220005012601260018013001300006013a013a0007013f013f00080002 +0067008800880015008900890016009400980004009b009e0007009f009f000800a000a1000300a200a2001700a300a3000a +00a400a7001700a900a9000b00aa00aa001800ab00ab000c00ac00ad001800b200b2001900b300b3000e00b400b4001a00b5 +00b5000f00b600b8001a00bb00bb001b00bc00bc001300bd00be001b00bf00bf001400c100c1001400c200c2001c00c300c3 +001d00c400c4001c00c500c5001d00c600c6001c00c700c7001d00c800c8000100c900c9001e00ca00ca001f00cb00cb0020 +00cc00cc001f00cd00cd002100ce00ce000100cf00cf001e00d000d0000200d100d1002200d300d3002300d500d5002400d7 +00d7002400d900d9002400db00db002400dd00dd000c00de00de001f00e000e0002500e100e1000d00e200e2001f00e400e4 +002600f100f1002700f500f5002700fb00fb000300ff00ff0003010a010a000e010e010e001f010f010f002801100110001f +011101110028011201120029011301130028011601160003011701170010011901190027011a011a0003011b011b0010011c +011c0005011e011e000501200120000501210121001101220122000501230123001101240124002a01250125002101260126 +000601270127001201280128002b012b012b002c012d012d002c012f012f002c01300130000701310131001301330133002c +01350135002c01360136002d01370137002e01380138002f013901390030013a013a0008013f013f000901880188002001ac +01ac003101ad01ad003201ae01ae003101af01af003201da01da000501dc01dc003301dd01dd002001f001f0001f01f101f1 +003401f301f3002001f401f4003501f501f5003600010000000a00c200d0001444464c54007a6172616200b461726d6e00b4 +6272616900b463616e7300b46368657200b46379726c00b467656f7200b46772656b00b468616e6900b46865627200b46b61 +6e6100b46c616f2000b46c61746e00846d61746800b46e6b6f2000b46f67616d00b472756e7200b474666e6700b474686169 +00b4000400000000ffff00000000000649534d2000284b534d2000284c534d2000284e534d200028534b5320002853534d20 +00280000ffff000100000000000000016c6f636c000800000001000000010004000100000001000800010006163a00010001 +010c00010000000a00e000e80050003c0c0007dd00000000028200000460000005d500000000000004600000000000000000 +0000000000000460000000000000016800000460000000550000000000000000000000000000000000000000000000000000 +0000000000000000010e0000027600000000000000000000000000000000000000000000000000000000000000000000005a +0000010e0000005a0000005a0000010e00000000000000000000010e0000005a0000005a0000010e0000005a0000005a0000 +005a000001720000005a0000005a000002380000fb8f0000003c00000000000000000028000a000a00000000000100000000 +0001040e019000050000053305990000011e05330599000003d7006602120000020b06030308040202040000000e00000000 +000000000000000050664564004000c5024f0614fe14019a076d01e30000000100000000000000000003000000030000001c +0000000a0000003c000300010000001c0004002000000004000400010000024fffff000000c5ffffffc2000100000000000c +00000000001c0000000000000001000000c50000024f00000087013500b800cb00cb00c100aa009c01a600b8006600000071 +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 +01cb05d5aafe46aafde3aa017ffe8105d59efcf00310ffff0073fe75052705f01226002600001007007a012d0000ffff00c9 +0000048b076b12260028000010071719049e0175ffff00c90000048b076b12260028000010071717049e0175ffff00c90000 +048b076d1226002800001107171a049e017500074003400c015d3100ffff00c90000048b074e12260028000011071716049e +017500094005400c4010025d3100ffff003b000001ba076b1226002c000010071719032f0175ffff00a20000021f076b1226 +002c000010071717032f0175fffffffe00000260076d1226002c00001107171a032f01750008b401060a00072b31ffff0006 +00000258074e1226002c000011071716032f01750008b4000a0701072b310002000a000005ba05d5000c0019006740201009 +a90b0d95008112950e0b0707011913040f0d161904320a110d1c0800791a10f43cec32c4f4ec10c4173931002fc632eef6ee +10ee32304028201b7f1bb01b039f099f0a9f0b9f0c9f0e9f0f9f109f11bf09bf0abf0bbf0cbf0ebf0fbf10bf11105d015d13 +21200011100029011123353313112115211133200011100021d301a001b10196fe69fe50fe60c9c9cb0150feb0f30135011f +fee1fecb05d5fe97fe80fe7efe9602bc9001e3fe1d90fdea0118012e012c0117ffff00c900000533075e1226003100001107 +171804fe01750014b400132204072b400930133f2210131f22045d31ffff0073ffe305d9076b122600320000100717190527 +0175ffff0073ffe305d9076b1226003200001007171705270175ffff0073ffe305d9076d1226003200001107171a05270175 +0010b40f1a1e15072b40051f1a101e025d31ffff0073ffe305d9075e12260032000011071718052701750018b40321300907 +2b400d30213f3020212f3010211f30065d31ffff0073ffe305d9074e12260032000011071716052701750014b4031f1a0907 +2b4009401f4f1a101f1f1a045d3100010119003f059c04c5000b0085404d0a9c0b0a070807099c080807049c030407070605 +9c060706049c0504010201039c0202010b9c0001000a9c090a010100420a080706040201000805030b090c0b0a0907050403 +0108020008060c10d43ccc321739310010d43ccc321739304b5358071008ed071005ed071005ed071008ed071005ed071008 +ed071005ed071008ed59220902070901270901370901059cfe3701c977fe35fe357601c8fe387601cb01cb044cfe35fe3779 +01cbfe357901c901cb79fe3501cb00030066ffba05e5061700090013002b009e403c1d1f1a0d2b2c130a0100040d29262014 +0d042a261e1a0495260d951a91268c2c2b2c2a141710201e23130a0100041d2910071f07192333101917102c10fcecfcecc0 +111239391739123939111239391139310010e4f4ec10ee10c010c011123939123912173912391112393930402a57005a1557 +1955216a1565217b15761c7521094613590056136a006413641c6a287c007313761c7a280b5d015d09011e01333200113426 +272e012322001114161707260235100021321617371707161215100021222627072704b6fd333ea15fdc010127793da15fdc +fefd2727864e4f0179013b82dd57a266aa4e50fe88fec680dd5ba2670458fcb240430148011a70b8b84043feb8fee570bc44 +9e660108a0016201a54d4bbf59c667fef69efe9ffe5b4b4bbf58ffff00b2ffe30529076b1226003800001007171904ee0175 +ffff00b2ffe30529076b1226003800001007171704ee0175ffff00b2ffe30529076d1226003800001107171a04ee01750014 +b40a141800072b40092f1420181f141018045d31ffff00b2ffe30529074e1226003800001107171604ee0175001cb4011914 +09072b401150195f1440194f1420192f1410191f14085d31fffffffc000004e7076b1226003c000010071717047301750002 +00c90000048d05d5000c0015003d401b0e95090d9502f600810b150f090304011219063f0d0a011c00041610fcec3232fcec +11173931002ff4fcecd4ec3040090f171f173f175f1704015d1333113332041514042b011123131133323635342623c9cafe +fb0101fefffbfecacafe8d9a998e05d5fef8e1dcdce2feae0427fdd192868691000100baffe304ac0614002f009a40302d27 +210c04060d2000042a1686171ab9132ab90397138c2e0c090d1d2021270908242708061d082410162d081000463010fcc4fc +cc10c6eed4ee10ee1139391239123931002fe4feee10fed5ee12173917393040400f050f060f070f270f288a0c8a0d070a06 +0a070a0b0a0c0a0d0a1f0d200a210c220426190d191f19203a203a214d1f4d20492149226a1f6a20a506a507a620185d015d +133436333216170e011514161f011e0115140623222627351e013332363534262f012e01353436372e01232206151123baef +dad0db0397a83a4139a660e1d3408849508c4174783b655c6057a7970883718288bb0471c8dbe8e00873602f512a256a8e64 +acb71918a41e1d5f5b3f543e373b875b7fac1d67708b83fb9300ffff007bffe3042d0666122600440000110600435200000b +40073f262f261f26035d3100ffff007bffe3042d0666122600440000110600765200000b40073f262f261f26035d3100ffff +007bffe3042d06661226004400001106028852000008b40b282c14072b31ffff007bffe3042d06371226004400001106029e +52000014b4142e3c0b072b4009202e2f3c102e1f3c045d31ffff007bffe3042d06101226004400001106006a52000020b414 +2d280b072b40157f286f28502d5f28402d4f28302d3f28002d0f280a5d31ffff007bffe3042d07061226004400001106029c +52000025400e262c142c260b0732381438320b072b10c42b10c4310040093f353f2f0f350f2f045d30000003007bffe3076f +047b00060033003e01034043272d253d0e0d0034a925168615881200a90e3a12b91c192e862dba2a03b90ebb07310ab81f19 +8c253f343726060f0025371c07260f1500080d3d26080f2d370822453f10fcecccd4fc3cd4ecc41112393911391112391112 +39310010c4e432f43cc4e4fc3cf4ec10c4ee3210ee10f4ee10ee11391139111239304081302b302c302d302e302f3030402b +402c402d402e402f4030502b502c502d502e502f5030852b853080409040a040b040c040d040e040e040f0401d3f003f063f +0d3f0e3f0f05302c302d302e302f402c402d402e402f502c502d502e502f6f006f066f0d6f0e6f0f602c602d602e602f702c +702d702e702f802c802d802e802f1d5d71015d012e0123220607033e013332001d01211e0133323637150e01232226270e01 +232226353436332135342623220607353e013332160322061514163332363d0106b601a58999b90e444ad484e20108fcb20c +ccb768c86464d06aa7f84d49d88fbdd2fdfb0102a79760b65465be5a8ed5efdfac816f99b9029497b4ae9e01305a5efeddfa +5abfc83535ae2a2c79777878bba8bdc0127f8b2e2eaa272760fe18667b6273d9b429ffff0071fe7503e7047b122600460000 +1007007a008f0000ffff0071ffe3047f066612260048000010070043008b0000ffff0071ffe3047f06661226004800001007 +0076008b0000ffff0071ffe3047f066612260048000011070288008b00000008b4151e221b072b31ffff0071ffe3047f0610 +1226004800001107006a008b0000000740034020015d3100ffffffc7000001a6066610270043ff1d0000120600f30000ffff +00900000026f066610270076ff1d0000120600f30000ffffffde0000025c0666122600f3000011070288ff1d00000008b401 +070b00072b31fffffff4000002460610122600f300001107006aff1d00000008b4000b0801072b3100020071ffe304750614 +000e00280127405e257b26251e231e247b23231e0f7b231e287b27281e231e262728272524252828272223221f201f212020 +1f42282726252221201f08231e030f2303b91b09b9158c1b23b1292627120c212018282523221f051e0f060c121251061218 +452910fcecf4ec113939173912393911123939310010ecc4f4ec10ee12391239121739304b535807100ec9071008c9071008 +c907100ec9071008ed070eed071005ed071008ed5922b23f2a01015d407616252b1f28222f232f2429252d262d272a283625 +462558205821602060216622752075217522132523252426262627272836243625462445255a205a21622062217f007f017f +027a037b097f0a7f0b7f0c7f0d7f0e7f0f7f107f117f127f137f147b157a1b7a1c7f1d7f1e762076217822a02af02a275d00 +5d012e0123220615141633323635342613161215140023220011340033321617270527252733172517050346325829a7b9ae +9291ae36097e72fee4e6e7fee50114dd12342a9ffec1210119b5e47f014d21fed903931110d8c3bcdedebc7abc01268ffee0 +adfffec9013700fffa01370505b46b635ccc916f6162ffff00ba0000046406371226005100001007029e00980000ffff0071 +ffe304750666122600520000100600437300ffff0071ffe304750666122600520000100600767300ffff0071ffe304750666 +1226005200001106028873000008b40f1a1e15072b31ffff0071ffe3047506371226005200001106029e73000014b415202e +0f072b400920202f2e10201f2e045d31ffff0071ffe3047506101226005200001106006a73000014b4031f1a09072b400940 +1f4f1a301f3f1a045d31000300d9009605db046f00030007000b0029401400ea0206ea0402089c040a0c090501720400080c +10dcd43cfc3cc4310010d4c4fcc410ee10ee3001331523113315230121152102dff6f6f6f6fdfa0502fafe046ff6fe12f502 +41aa00030048ffa2049c04bc00090013002b00e4403c2b2c261f1d1a130a0100040d292620140d042a261e1a04b9260db91a +b8268c2c2b2c2a141710201e23130a01000410071f1d0712235129101217452c10fcec32f4ec32c011121739123939111239 +391139310010e4f4ec10ee10c010c011123939123912173911393911123930407028013f2d5914561c551d56206a1566217f +007b047f057f067f077f087f097f0a7f0b7f0c7b0d7a157b1a7f1b7f1c7f1d7f1e7f1f7f207b217f227f237f247f257b269b +199525a819a02df02d2659005613551d5a2869006613651c6a287a007413761c7a28891e95189a24a218ad24115d015d0901 +1e01333236353426272e0123220615141617072e01351000333216173717071e011510002322262707270389fe1929674193 +ac145c2a673e97a913147d36360111f15d9f438b5f923536feeef060a13f8b600321fdb02a28e8c84f759a2929ebd3486e2e +974dc577011401383334a84fb34dc678feedfec73433a84effff00aeffe304580666122600580000100600437b00ffff00ae +ffe304580666122600580000100600767b00ffff00aeffe304580666122600580000110602887b000008b40b171b01072b31 +ffff00aeffe3045806101226005800001106006a7b000018b4021b180a072b400d401b4f18301b3f18001b0f18065d31ffff +003dfe56047f06661226005c0000100600765e00000200bafe5604a406140010001c003e401b14b905081ab9000e8c08b801 +bd03971d11120b471704000802461d10fcec3232f4ec310010ece4e4f4c4ec10c6ee304009601e801ea01ee01e04015d2511 +231133113e013332001110022322260134262322061514163332360173b9b93ab17bcc00ffffcc7bb10238a79292a7a79292 +a7a8fdae07befda26461febcfef8fef8febc6101ebcbe7e7cbcbe7e7ffff003dfe56047f06101226005c00001106006a5e00 +0016b418171219072b400b30173f1220172f121f12055d31ffff00100000056807311027007100bc013b1306002400000010 +b40e030209072b400540034f02025d31ffff007bffe3042d05f6102600714a001306004400000010b41803020f072b40056f +027f03025d31ffff00100000056807921027029a00ce014a1306002400000012b418000813072b310040056f006f08025d30 +ffff007bffe3042d061f1026029a4fd71306004400000008b422000819072b31ffff0010fe7505a505d51226002400001007 +029d02e40000ffff007bfe750480047b1226004400001007029d01bf0000ffff0073ffe30527076b12260026000010071717 +052d0175ffff0071ffe303e706661226004600001007007600890000ffff0073ffe30527076d1027171a054c017513060026 +00000009b204041e103c3d2f3100ffff0071ffe303e706661226004600001007028800a40000ffff0073ffe3052707501027 +171e054c0175120600260000ffff0071ffe303e70614102702b804a40000120600460000ffff0073ffe30527076d12260026 +00001107171b052d0175000740031f1d015d3100ffff0071ffe303e706661226004600001007028900890000ffff00c90000 +05b0076d1027171b04ec0175120600270000ffff0071ffe305db06141226004700001107171505140000000b40075f1d3f1d +1f1d035d3100ffff000a000005ba05d510060092000000020071ffe304f4061400180024004a40240703d30901f922b90016 +1cb90d108c16b805970b021f0c04030008080a0647191213452510fcecf43cc4fc173cc431002fece4f4c4ec10c4eefd3cee +3230b660268026a02603015d01112135213533153315231123350e0123220211100033321601141633323635342623220603 +a2feba0146b89a9ab83ab17ccbff00ffcb7cb1fdc7a79292a8a89292a703b6014e7d93937dfafca864610144010801080144 +61fe15cbe7e7cbcbe7e7ffff00c90000048b07331226002800001007007100a1013dffff0071ffe3047f05f6102700710096 +0000130600480000000740037000015d3100ffff00c90000048b076d1027171d04a10175130600280000000740034000015d +3100ffff0071ffe3047f06481027029a00960000130600480000000740037000015d3100ffff00c90000048b07501027171e +049e0175120600280000ffff0071ffe3047f0614102702b804960000120600480000ffff00c9fe75048d05d5122600280000 +1007029d01cc0000ffff0071fe75047f047b1226004800001007029d01780000ffff00c90000048b07671226002800001107 +171b04a6016f00074003400c015d3100ffff0071ffe3047f0661122600480000110702890094fffb0010b400211d0f072b40 +050f21001d025d31ffff0073ffe3058b076d1027171a055c01751306002a00000009b2040415103c3d2f3100ffff0071fe56 +045a06661026028868001306004a00000009b204040a103c3d2f3100ffff0073ffe3058b076d1226002a00001007171d051b +0175ffff0071fe56045a06481226004a00001007029a008b0000ffff0073ffe3058b07501027171e055c01751306002a0000 +00080040033f00015d30ffff0071fe56045a0614102702b8046a00001206004a0000ffff0073fe01058b05f0102702d7055e +ffed1206002a0000ffff0071fe56045a0634102702c303e0010c1206004a0000ffff00c90000053b076d1027171a05020175 +1306002b00000014b40c020607072b40092f0220061f021006045d31ffffffe500000464076d1027171a031601751306004b +0000002ab414020613072b31004bb00e5158bb0014ffc00013ffc0383859400d901490138014801340144013065d000200c9 +0000068b05d500130017003a401e060212950914110c9515ad0400810e0a070c17041c0538120d14011c001810dcec3232cc +fcec3232cc31002f3ce432fcecdc3232ec3232300133152135331533152311231121112311233533171521350171ca02deca +a8a8cafd22caa8a8ca02de05d5e0e0e0a4fbaf02c7fd390451a4a4e0e000000100780000049f0614001b003e402103090003 +16010e12870d1506871619b810970a010208004e130e11150908100b1c10dc32ec3232ccccf4ec31002f3cecf4c4ecdc32ec +32111217393001112311342623220615112311233533353315211521113e01333216049fb87c7c95acb97d7db90160fea042 +b375c1c602a4fd5c029e9f9ebea4fd8704f6a47a7aa4febc6564ef00ffffffe400000278075e10271718032e01751306002c +00000008b41e09181f072b31ffffffd30000026706371027029eff1d0000130600f300000008b41c08161d072b31ffff0003 +00000259073110270071ff2e013b1306002c00000008b404030205072b31fffffff20000024805f510270071ff1dffff1306 +00f300000008b404030205072b31fffffff500000267076d1027171d032e01751306002c00000008b40e00080f072b31ffff +ffe40000025606481027029aff1d0000130600f300000008b40e00080f072b31ffff00b0fe75022505d51027029dff640000 +1206002c0000ffff0096fe75020b06141027029dff4a00001206004c0000ffff00c90000019507501226002c00001107171e +032f01750013b306010700103c103c3100b43f073f06025d3000000200c100000179047b00030004002c400b04b800bf0204 +010800460510fcec3931002fece43040110404340444041006400650066006700608015d1333112313c1b8b85c0460fba004 +7b00ffff00c9fe6603ef05d51027002d025c00001106002c00000008400311040110ec31ffff00c1fe5603b106141027004d +023800001106004c00000008400319460110ec31ffffff96fe66025f076d1027171a032e01751306002d00000008b4080206 +07072b31ffffffdbfe56025c066610270288ff1d0000130601f900000008b408020607072b31ffff00c9fe1e056a05d51027 +02d7051b000a1206002e0000ffff00bafe1e049c0614102702d704ac000a1206004e0000000100ba0000049c0460000a00bb +4028081105060507110606050311040504021105050442080502030300bc09060501040608010800460b10fcec32d4c41139 +31002f3cec321739304b5358071004ed071005ed071005ed071004ed5922b2100c01015d405f04020a081602270229052b08 +56026602670873027705820289058e08930296059708a3021209050906020b030a072803270428052b062b07400c6803600c +8903850489058d068f079a039707aa03a705b607c507d607f703f003f704f0041a5d71005d1333110133090123011123bab9 +0225ebfdae026bf0fdc7b90460fe1b01e5fdf2fdae0221fddf00ffff00c90000046a076c10271717036e01761206002f0000 +ffff00c10000024a076c10271717035a01761306004f0000001eb10304103c31004bb00e5158b900000040385940079f008f +004f00035d30ffff00c9fe1e046a05d5102702d7049b000a1206002f0000ffff0088fe1e01ad0614102702d7031e000a1306 +004f0000000740034000015d3100ffff00c90000046a05d510271715029fffc31206002f0000ffff00c10000030006141027 +1715023900021106004f0000000940058f001f00025d3100ffff00c90000046a05d510270079023100771206002f0000ffff +00c10000028406141027007900d600731106004f000000174bb00d514bb011534bb018515a5b58b900000040385931000001 +fff20000047505d5000d003f401e0c0b0a040302060006950081080304010b0e000405011c0c073a0900790e10f43cecc4fc +3cc411123911123931002fe4ec11173930b4300f500f02015d1333112517011121152111072737d3cb013950fe7702d7fc5e +944de105d5fd98db6ffeeefde3aa023b6a6e9e0000010002000002480614000b005e401a0a09080403020600970603040109 +0a00047a0501080a7a07000c10d43ce4fc3ce411123911123931002fec173930014bb0105458bd000c00400001000c000cff +c038113738594013100d400d500d600d73047a0a700de00df00d095d133311371707112311072737c7b87d4cc9b87b4ac506 +14fda65a6a8dfce3029a586a8d00ffff00c900000533076c1027171704c50176130600310000000740034f00015d3100ffff +00ba00000464066d102600764207130600510000000940053f004f00025d3100ffff00c9fe1e053305d5102702d70500000a +120600310000ffff00bafe1e0464047b102702d70490000a120600510000ffff00c900000533075f1226003100001107171b +04f501670014b4040f0b00072b40092f0f200b1f0f100b045d31ffff00ba00000464066612260051000011070289008d0000 +0010b40019150c072b40050f190015025d31ffff00cd000005b905d510270051015500001006027e1b00000100c9fe560519 +05f0001c003b400d191612181c1c120a051c07411d10fc4bb0105458b90007ffc03859ec32d4fccc113100400c199516b007 +02950e910881072fe4f4ec10f4ec30011021220615112311331536373633321219011407062b0135333236350450fecdb3d7 +caca4e696a99e3e95152b55731664f037f01acffdefcb205d5f1864343fec1feccfc6fd561609c5aa000000100bafe560464 +047b001f003b401c0d13000318150787061087181cb816bc15070d08004e13170816462010fcec32f4ecc431002fe4f4c4ec +d4ec1112173930b46021cf2102015d01111407062b0135333237363511342623220615112311331536373633321716046452 +51b5fee96926267c7c95acb9b942595a75c1636302a4fd48d660609c30319902b29f9ebea4fd870460ae653232777800ffff +0073ffe305d90731102700710127013b1306003200000010b40d020307072b40051f021003025d31ffff0071ffe3047505f5 +1026007173ff1306005200000008b413020319072b31ffff0073ffe305d9076d1027171d052701751306003200000010b411 +000817072b400510001f08025d31ffff0071ffe3047506481026029a73001306005200000008b41d080023072b31ffff0073 +ffe305d9076b1027171f05270175120600320000ffff0071ffe3047506661027029f00a00000120600520000000200730000 +080c05d500100019003b401f059503110195008118079503ad091812100a1506021c1100040815190d101a10fcecd4c4c4d4 +ec32123939393931002fecec32f4ec3210ee30011521112115211121152120001110002117232000111000213307fafd1a02 +c7fd3902f8fbd7fe4ffe4101bf01b16781febffec0014001418105d5aafe46aafde3aa017c0170016d017caafee1fee0fedf +fedf00030071ffe307c3047b0006002700330084403107080010860f880c00a9082e0cb916132803b908bb22251fb819138c +340600162231090f0008074b311209512b121c453410fcecf4fcf4ecc4111239391239310010e432f43cc4e4ec3210c4ee32 +10ee10f4ee1112393040253f355f3570359f35cf35d035f035073f003f063f073f083f09056f006f066f076f086f09055d71 +015d012e01232206070515211e0133323637150e01232226270e01232200111000333216173e013332002522061514163332 +36353426070a02a48999b90e0348fcb20cccb76ac86264d06aa0f25147d18cf1feef0111f18cd3424ee88fe20108fab094ac +ab9593acac029498b3ae9e355abec73434ae2a2c6e6d6e6d01390113011401386f6c6b70fedd87e7c9c9e7e8c8c7e900ffff +00c900000554076c1027171704950176120600350000ffff00ba00000394066d102600764207120600550000ffff00c9fe1e +055405d5102702d70510000a120600350000ffff0082fe1e034a047b102702d70318000a120600550000ffff00c900000554 +075f1226003500001107171b047d016700080040035f1d015d30ffff00ba0000035a0666122600550000110602891b000010 +b411171309072b40050f170013025d31ffff0087ffe304a2076c1027171704950176120600360000ffff006fffe303c7066d +102600764207120600560000ffff0087ffe304a2076d1027171a04930175130600360000000bb404201529291049633a3100 +ffff006fffe303c70666102602882500130600560000000bb404201529291049633a3100ffff0087fe7504a205f012260036 +00001007007a008b0000ffff006ffe7503c7047b1226005600001006007a1700ffff0087ffe304a2076d1226003600001107 +171b048b0175000bb42b200e22221049633a3100ffff006fffe303c70666122600560000110702bd04270000000bb42b200e +22221049633a3100fffffffafe7504e905d51026007a5000120600370000ffff0037fe7502f2059e1026007ae10012060057 +0000fffffffa000004e9075f1226003700001107171b047301670010b4010d0900072b310040035f08015d30ffff00370000 +02fe06821226005700001107171502370070000740038f14015d31000001fffa000004e905d5000f00464018070b95040c09 +030f9500810905014007031c0c00400a0e1010d43ce4ccfc3ce4cc31002ff4ec3210d43cec323001401300111f0010011002 +1f0f1011401170119f11095d032115211121152111231121352111210604effdee0109fef7cbfef70109fdee05d5aafdc0aa +fdbf0241aa02400000010037000002f2059e001d0043401f0816a90517041aa900011bbc0d8710100d0e020608040008171b +15191d461e10fc3c3cc432fc3c3cc4c432393931002fecf43cc4fc3cdc3cec3230b2af1f01015d0111211521152115211514 +17163b0115232227263d0123353335233533110177017bfe85017bfe85252673bdbdd5515187878787059efec28fe98ee989 +27279a504fd2e98ee98f013effff00b2ffe30529075e1027171804ee01751306003800000010b41f091827072b400510091f +18025d31ffff00aeffe3045806371027029e008300001306005800000008b41e081626072b31ffff00b2ffe3052907311027 +007100ee013b1306003800000014b40503020d072b40092f0220031f021003045d31ffff00aeffe3045805f5102700710083 +ffff1306005800000008b40603020e072b31ffff00b2ffe30529076d1027171d04ee01751306003800000010b40f00081707 +2b400510001f08025d31ffff00aeffe3045806481027029a008300001306005800000008b410000818072b31ffff00b2ffe3 +0529076f1226003800001007029c00f00069ffff00aeffe3045806ca1226005800001106029c7cc40009400540154021025d +3100ffff00b2ffe30529076b1027171f04ee0175120600380000ffff00aeffe3045e06661027029f00b00000120600580000 +ffff00b2fe75052905d51226003800001007029d00fa0000ffff00aefe7504e8047b1226005800001007029d02270000ffff +0044000007a607741027171a05f5017c1306003a00000008b415020614072b31ffff005600000635066d1027028801450007 +1306005a00000008b415020614072b31fffffffc000004e707741027171a0472017c1306003c00000008b40b020607072b31 +ffff003dfe56047f066d102602885e071306005c00000008b418020617072b31fffffffc000004e7074e1226003c00001107 +1716047301750008b400100b04072b31ffff005c0000051f076c10271717049501761206003d0000ffff0058000003db066d +1026007642071206005d0000ffff005c0000051f07501027171e04be01751206003d0000ffff0058000003db0614102702b8 +041700001306005d0000000e0140094f0a5f0aaf0adf0a045d31ffff005c0000051f076d1226003d00001007171b04be0175 +ffff0058000003db06661226005d0000110602891b000010b4010f0b00072b40050f0f000b025d310001002f000002f80614 +0010002340120b870a970102a905bc010a10080406024c1110fc3cccfccc31002ff4ec10f4ec302123112335333534363b01 +1523220706150198b9b0b0aebdaeb063272603d18f4ebbab9928296700020020ffe304a40614000f002c0044402504b91014 +0cb9201c8c14b8222925a92c242797222e45001218472a20062c2808252327462d10fc3cccec323232ccf4ecec31002ff4dc +3cec3210e4f4c4ec10c6ee300134272623220706151417163332373601363736333217161110070623222726271523112335 +3335331521152103e5535492925453535492925453fd8e3a59587bcc7f80807fcc7b58593ab99a9ab90145febb022fcb7473 +7374cbcb747373740252643031a2a2fef8fef8a2a2313064a805047d93937d000003ff970000055005d50008001100290043 +40231900950a0995128101950aad1f110b080213191f05000e1c1605191c2e09001c12042a10fcec32fcecd4ec1117393939 +31002fececf4ec10ee3930b20f2201015d01112132363534262301112132363534262325213216151406071e011514042321 +1122061d012335343601f70144a39d9da3febc012b94919194fe0b0204e7fa807c95a5fef0fbfde884769cc002c9fddd878b +8c850266fe3e6f727170a6c0b189a21420cb98c8da05305f693146b5a300ffff00c9000004ec05d5120603a50000000200ba +ffe304a40614001600260038401f1bb9000423b9100c8c04b81216a913971228451417120847101f160813462710fcec3232 +f4ecc4ec31002ff4ec10e4f4c4ec10c6ee300136373633321716111007062322272627152311211525013427262322070615 +1417163332373601733a59587bcc7f80807fcc7b58593ab9034efd6b027253549292545353549292545303b6643031a2a2fe +f8fef8a2a2313064a80614a601fcc0cb74737374cbcb7473737400020000000004ec05d5000a00170033400c170b19001910 +2e050b1c15162fdcec32fcecc410cc31400905950cad0b81069514002fece4f4ecb315150b141112392f3001342726232111 +213237360111213204151404232111230104174f4ea3febc0144a34e4ffd7c014efb0110fef0fbfde8c9013801b78b4443fd +dd444304a8fd9adadeddda044401910000020000ffe304a406150012001e003e400d111220131206470d1912080f102fdcec +3232f4ecc410cc31400e0016b903b80e0c1cb9098c11970e002fe4f4ecc410f4ecc4b30f0f110e1112392f30013e01333200 +1110022322262715231123013301342623220615141633323601733ab17bcc00ffffcc7bb13ab9ba0122510272a79292a7a7 +9292a703b66461febcfef8fef8febc6164a8044401d1fc1acbe7e7cbcbe7e70000010073ffe3052705f000190030401b1986 +0088169503911a0d860c881095098c1a1b10131906300d001a10dc3cf4ecec310010f4ecf4ec10f4ecf4ec30133e01332000 +11100021222627351e01332000111000212206077368ed8601530186fe7afead84ed6a66e78201000110fef0ff0082e76605 +624747fe61fe98fe99fe614848d35f5e01390127012801395e5f00010073ffe3065a0764002400444022219520250da10eae +0a951101a100ae04951791118c25200719141b110d003014102510fcfc32ec10ecc4310010e4f4ecf4ec10eef6ee10dcec30 +b40f261f2602015d01152e0123200011100021323637150e0123200011100021321716173637363b0115232206052766e782 +ff00fef00110010082e7666aed84feadfe7a01860153609c0d0c105366e34d3f866e0562d55f5efec7fed8fed9fec75e5fd3 +4848019f01670168019f240304c3627aaa9600010071ffe304cc06140022004e402400860188040e860d880ab91104b917b8 +118c2301871e972307121419081e0d004814452310fcf432ccec10ec310010f4ec10e4f4ec10fef4ee10f5ee30400b0f2410 +2480249024a02405015d01152e0123220615141633323637150e012322001110002132173534363b011523220603e74e9d50 +b3c6c6b3509d4e4da55dfdfed6012d01064746a1b54530694c047ef52b2be3cdcde32b2baa2424013e010e0112013a0c0fd6 +c09c6100ffff000a000005ba05d51006009200000002ff970000061405d50008001a002e4015009509810195100802100a00 +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 +f4aa96c2ffff00bafe560464047b1006034b000000030073ffe305d905f0000b001200190031400b19101906330f13190010 +1a10fcec32f4ec323100400f16950913950fad1a0c950391098c1a10e4f4ec10f4ec10ec3013100021200011100021200001 +220007212602011a0133321213730179013a013b0178fe88fec5fec6fe8702b5caff000c03ac0efefd5608fbdcdcf80802e9 +016201a5fe5bfe9ffe9efe5b01a403c5fee4c3c3011cfd7afefffec2013d0102ffff0067ffe3061d061410260032f4001007 +02cc05a20134ffff0076ffe304d304eb102702cc0458000b10060052050000020073ffe306cf05f00014001f0033401c0495 +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 +043f1e1eac9e8295240f25504b51593535be2323b69c89992a0e2149405454282800ffff00c90000048b05d5100603370000 +0002fef2fe5602d706140016001f0036400c1d0e0a1506140108170a4f2010fc32fc32cccc10d4cc3100400f141f87000b1b +87109720048706bd2010fcec10f4ecd43cec3230011114163b01152322263511232035342132171617331525262726232207 +063301774d63b0aebdaebefef2012fb5523512bffe860811216e7c030377046afb3d685099abbb04aed2d860406f9b9a2c18 +3041330000010037fe5602f2059e001d003f400e0e14080802090400081a1c18461e10fc3cc4fc3cdc3239fccc3100401218 +05081903a9001b01bc08871510870ebd152ffcec10ecf43cccec321139393001112115211114163b011514062b0135333237 +363d0122263511233533110177017bfe854b73bda4b446306a2626d5a78787059efec28ffda0894eaed6c09c303199149fd2 +02608f013e0000010018000004e905d5000f005840150d0a0c06029500810400070140031c050b1c0d051010d4d4ec10fce4 +393931002ff4ec32c4393930014bb00a5458bd00100040000100100010ffc03811373859401300111f00100110021f071011 +401170119f11095d012115211123112322061d012335343601ae033bfdeecb5e84769cc005d5aafad5052b5a693146b5a300 +00010037000002f20614001b0049401019160b080417090204000810130e461c10fc3cc4fc3cc43232173931004013130019 +8716970a0e05080f03a91101bc08870a2fecf43cec3211393910f4ec393930b2af1501015d01152115211114163b01152322 +2635112335333534363b01152322060177017bfe854b73bdbdd5a28787aebdaeb0634d04c3638ffda0894e9a9fd202608f4e +bbab99510001fffafe6604e905d5000f0054401407950abd100e0295008110080140031c00400d1010d4e4fce4c4310010f4 +ec3210f4ec30014bb00a5458bd00100040000100100010ffc03811373859401300111f00100110021f0f1011401170119f11 +095d032115211114163b01152322261901210604effdee6e863f4ee3cdfdee05d5aafb3dc296aaf4010e04c3ffff00adfff7 +065f061410260038fb14100702cc05e40134ffff00b0ffe3056904eb102702cc04ee000b1006005802000001004effe305cf +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 +05f00506015d13331123c9caca05d5f88100ffff00c9fe56032705d5102701820194000010060182000000010014fe56039c +05d50013003a401d0c09a90f061302a91005050a00970abd14070309050108120d0c10001410d43c3ccc32fc3c3ccc323100 +10ecec11392f3cec32dc3cec323001331121152115211521112311213521352135210173ca015ffea1015ffea1cafea1015f +fea1015f05d5fd97a8f0aafd2c02d4aaf0a8ffff00c90000019405d5100600049400ffff00c900000ad0076d1027013f05b1 +0000100600270000ffff00c9000009b006661027014005d50000100600270000ffff0071ffe3089106661027014004b60000 +100600470000ffff00c9fe66062405d51027002d049100001006002f0000ffff00c9fe5605de06141027004d046500001006 +002f0000ffff00c1fe5602ef06141027004d017600001006004f0000ffff00c9fe6606f205d51027002d055f000010060031 +0000ffff00c9fe5606b706141027004d053e0000100600310000ffff00bafe5605de06141027004d04650000100600510000 +ffff001000000568076d1226002400001107171b04be01750006b10e00103c31ffff007bffe3042d06661226004400001106 +02895a000008b40b2b2714072b31fffffffe00000260076d1226002c00001107171b032f0175000bb407200100001049633a +3100ffffffe00000025e0666122600f3000011070289ff1f0000000bb408200100001049633a3100ffff0073ffe305d9076d +1226003200001007171b05270175ffff0071ffe3047506661226005200001106028976000006b11b0c103c31ffff00b2ffe3 +0529076d1226003800001107171b04f601750006b11505103c31ffff00aeffe304580666122600580000110602897600000b +b418200b01011049633a3100ffff00b2ffe305290833102617493000120600380000ffff00aeffe30458073110270071007b +013b120600be0000ffff00b2ffe30529085a1226003800001006174c3600ffff00aeffe3045807221226005800001007174c +ffbefec8ffff00b2ffe30529085a122600380000100617513000ffff00aeffe30458072212260058000010071751ffc4fec8 +ffff00b2ffe3052908601226003800001006174d3006ffff00aeffe3045807221226005800001007174dffbefec8ffff0071 +ffe3047f047b1206021b0000ffff0010000005680833122600240000100617490000ffff007bffe3042d0731122600a60000 +100700710052013bffff00100000056808331226002400001006174b0000ffff007bffe3042d06f41226004400001007174b +ff93fec1ffff00080000074807341027007102d7013e120600880000ffff007bffe3076f05f21027007101e8fffc120600a8 +000000010073ffe3060405f00025005440102124221e1c11340200043318190b102610fcecfc3ccce4fcc4c431004018041f +012200051b2395251b950812a111ae15950e91088c2610e4f4ecf4ec10fed4ee113939dcb00b4b5458b1224038593ccc3230 +011133152315060423200011100021320417152e012320001110002132363735233533352135058b797975fee6a0fea2fe75 +018b015e9201076f70fc8bfeeefeed011301126ba843fdfdfeb6030cfed658ff53550199016d016e01994846d75f60fecefe +d1fed2fece2527b55884a60000020071fe5604fa047b000b00340058400e0f22322500080c470612182c453510fcc4ecf4ec +3232c4c43100401b20110e23250c29091886191cb91503b9322fb833bc09b915bd26292fc4e4ece4f4c4ec10fed5ee111239 +39d43ccc3230b660368036a03603015d01342623220615141633323617140733152306070621222627351e01333237363721 +3521363d010e0123220211101233321617353303a2a59594a5a59495a5b813b3c61f3a7ffefa61ac51519e52b55a1511fd84 +029a1639b27ccefcfcce7cb239b8023dc8dcdcc8c7dcdceb6e58465d408c1d1eb32c2a5f171c45475e5b6362013a01030104 +013a6263aa00ffff0073ffe3058b076d1226002a00001107171b054a01750010b1210e103c4007942154212421035d31ffff +0071fe56045a0663102602894afd1206004a0000ffff00c90000056a076d1027171b04a201751206002e0000ffffffe90000 +049c076d1226004e00001107171b031a0175002ab401100c00072b31004bb00e5158bb0001ffc00000ffc0383859400d9001 +90008001800040014000065dffff0073fe7505d905f01027029d01340000120600320000ffff0071fe750475047b1027029d +00800000120600520000ffff0073fe7505d90731102700710127013b120601ac0000ffff0071fe75047505f51026007173ff +120601ad0000ffff00a0ffc104f8076d1027171b04be0175120601790000ffff0058fe4c042f0666102602891b0010060254 +0000ffffffdbfe560264066610270289ff250000110601f90000000bb403200807071049633a3100ffff00c900000ad005d5 +1027003d05b10000100600270000ffff00c9000009b005d51027005d05d50000100600270000ffff0071ffe3089106141027 +005d04b60000100600470000ffff0073ffe3058b076c10271717051b01761206002a0000ffff0071fe56045a06631226004a +0000100600761bfd000100c9ffe3082d05d5001d0035400e0e1c1119031c06381b011c00041e10fcec32fcec32d4ec310040 +0e0f1a9502ad0400811c0a95158c1c2fe4ec10e432fcecc43013331121113311141716173237363511331114070621202726 +3511211123c9ca02deca3e3d9994423eca6460fee6feed6764fd22ca05d5fd9c0264fbec9f504e014f4ba4029ffd5adf8078 +7876e9010dfd3900000200c9fe56050205f0000e00170040400b19111c0d0417001c02041810fcec3232d4eccc3100400c42 +159505098c03810001bd1810ecc4f4f4ccec304b5358b617050f8700000e070410ed0010cc59251123113315363736333217 +1615100100113427262322030193caca389157e2c65354fc9102a13d3c81edba9cfdba077fb9485735787aa4fe37fece01ae +010c8f4746feff00ffff00c900000533076b10271719051e0175120600310000ffff00ba0000046406641226005100001007 +00430118fffeffff001000000568077312260087000010071717065c017dffff007bffe304dc0773122600a7000010071717 +05ec017dffff000800000748076c10271717065c0176120600880000ffff007bffe3076f0663122600a80000100700760165 +fffdffff0066ffba05e5076c1027171704fe01761206009a0000ffff0048ffa2049c0663122600ba0000100600761cfdffff +00100000056807701226002400001007172004e5017affff007bffe3042d0664102702c00498fffe120600440000ffff0010 +0000056807361226002400001007171c04bc013effff007bffe3042d0648102702c204650000120600440000ffff00c90000 +048b07701226002800001007172004a5017affff0071ffe3047f0663102702c004bafffd120600480000ffff00c90000048b +07361226002800001007171c04a6013effff0071ffe3047f0648102702c204a90000120600480000ffffffa7000002730770 +1226002c0000100717200359017affffffc3000002810663102702c00366fffd120600f30000ffff00050000027707361226 +002c00001007171c033e013effffffe3000002550648102702c203240000120600f30000ffff0073ffe305d9077012260032 +0000100717200541017affff0071ffe304750664102702c0049ffffe120600520000ffff0073ffe305d90736122600320000 +1007171c051c013effff0071ffe304750648102702c204980000120600520000ffff00c70000055407701226003500001007 +17200479017affff00820000034a0663102702c00425fffd120600550000ffff00c90000055407361226003500001007171c +0480013effff00ba0000035e0648102702c2042d0000120600550000ffff00b2ffe305290770122600380000100717200515 +017affff00aeffe304580664102702c004d4fffe120600580000ffff00b2ffe3052907361226003800001007171c04ec013e +ffff00aeffe304580648102702c204ab0000120600580000ffff0087fe1404a205f0102702d704760000120600360000ffff +006ffe1403c7047b102702d7042c0000120600560000fffffffafe1404e905d5102702d704530000120600370000ffff0037 +fe1402f2059e102702d7040000001206005700000001009cfe52047305f0002e0000010411140e010c01073536243e013534 +2623220f0135373e0335342e03232207353633321e0115140e02033f01346fb9ff00feea99c80131b95c7d705f73a3f83c66 +683d23374b4826b8f3efce83cb7c173a6e02a243fedb70cea0886022a0378c999d4f65843348ab6a1a41638b52375633220c +b8bea456b6803c66717400010047fe4f03bc047b00340000011e0315140e0507353e0435342623220f0135373e0435342e03 +23220607352433321e0115140602a746703e21426c989db3954aa2f59e6328765d3b3fd8df2241573f2d1f3143412345a893 +010a8670b8746701cd08445a58254b8a6c61463d270f822e605b625b33587019568b550d203c4566392c462a1b0a3b5a9a85 +4792616e9900ffff00c90000053b076d1027171b050401751206002b0000fffffff000000464076d1027171b032101751306 +004b0000002ab414050113072b31004bb00e5158bb0014ffc00013ffc0383859400d901490138014801340144013065d0001 +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 +a8fcdb00ffff00100000056807501027171e04bc0175120600240000ffff007bffe3042d0614102702b8044a000012060044 +0000ffff00c9fe75048b05d51226002800001007007a00a20000ffff0071fe75047f047b1226004800001006007a7b00ffff +0073ffe305d90833122600320000100617496200ffff0071ffe304750731122600b80000100700710073013bffff0073ffe3 +05d90833122600320000100617506900ffff0071ffe3047506e912260052000010071750ffb5feb6ffff0073ffe305d90750 +1027171e05270175120600320000ffff0071ffe304750614102702b804730000120600520000ffff0073ffe305d908331226 +003200001006174b6a00ffff0071ffe304750731122601f10000100700710073013bfffffffc000004e70731102700710072 +013b1206003c0000ffff003dfe56047f05f5102600715eff1206005c00000002008aff70035c060e00070019000025163332 +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 +100603300000000300c9ff42048b069300130017001b00000133073315230321152103211521072337231121011323110113 +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 +4b4b8f844b4aa601f393a800ffff00b203fe01d705d510060afb0000000100c104ee033f066600060037400c040502b400b3 +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 +fb83047dfa17d660609c3031ad047dfb8300ffff0192066303e808331027007100bd023d1007171604bc0155ffff0192065e +03e808331027171e04bc01501007007100bd023dffff0193066303e5085a1027171704f002641007171604bc0155ffff0193 +066303e5085a10271719048c02641007171604bc0155ffff0176066a040a08331027171804c0015c1007007100bd023dffff +018b066303ed085a1027171b04bc02621007171604bc0155000100000002599902d562eb5f0f3cf5001f080000000000d17e +0ee400000000d17e0ee4f7d6fc4c0e5909dc00000008000000000000000000010000076dfe1d00000efef7d6fa510e590001 +0000000000000000000000000000175104cd00660000000002aa0000028b0000033501350000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000057900100000000005960073062900c9050e00c90000000006330073060400c9025c00c9025cff96 +053f00c9047500c90000000005fc00c9064c00730000000000000000058f00c90514008704e3fffa05db00b20000000007e9 +00440000000004e3fffc057b005c0000000000000000000000000000000000000000040000aa04e7007b0000000004660071 +0514007104ec00710000000005140071051200ba023900c10239ffdb04a200ba023900c100000000051200ba04e500710000 +000000000000034a00ba042b006f03230037051200ae00000000068b00560000000004bc003d043300580000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000040000d7000000000000 +000000000000000000000000000000000000040000d500000000000000000000000000000000040001730000000000000000 +028b00db04000123000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000579001007cb000805960073050e00c9050e00c9050e00c9050e00c9025c003b025c00a2025cfffe025c0006 +0633000a05fc00c9064c0073064c0073064c0073064c0073064c007306b40119064c006605db00b205db00b205db00b205db +00b204e3fffc04d700c9050a00ba04e7007b04e7007b04e7007b04e7007b04e7007b04e7007b07db007b0466007104ec0071 +04ec007104ec007104ec00710239ffc7023900900239ffde0239fff404e50071051200ba04e5007104e5007104e5007104e5 +007104e5007106b400d904e50048051200ae051200ae051200ae051200ae04bc003d051400ba04bc003d0579001004e7007b +0579001004e7007b0579001004e7007b05960073046600710596007304660071059600730466007105960073046600710629 +00c9051400710633000a05140071050e00c904ec0071050e00c904ec0071050e00c904ec0071050e00c904ec0071050e00c9 +04ec00710633007305140071063300730514007106330073051400710633007305140071060400c90512ffe5075400c9058f +0078025cffe40239ffd3025c00030239fff2025cfff50239ffe4025c00b002390096025c00c9023900c104b800c9047200c1 +025cff960239ffdb053f00c904a200ba04a200ba047500c9023900c1047500c902390088047500c9030000c1047500c902bc +00c1047ffff20246000205fc00c9051200ba05fc00c9051200ba05fc00c9051200ba068200cd05fc00c9051200ba064c0073 +04e50071064c007304e50071064c007304e50071088f0073082f0071058f00c9034a00ba058f00c9034a0082058f00c9034a +00ba05140087042b006f05140087042b006f05140087042b006f05140087042b006f04e3fffa0323003704e3fffa03230037 +04e3fffa0323003705db00b2051200ae05db00b2051200ae05db00b2051200ae05db00b2051200ae05db00b2051200ae05db +00b2051200ae07e90044068b005604e3fffc04bc003d04e3fffc057b005c04330058057b005c04330058057b005c04330058 +02d1002f0514002005e1ff97057d00c9051400ba057d00000514000005a0007305960073046600710633000a068dff97057d +00c90514007104e50071050e0083064c007504ea00a4049aff9602d1ff7f06330073057e000807df00ba02d400c9025c000a +05f700c904a200b90239000a04bc003d07cb00b205fcff96051200ba064c0073074e006704e5007607970073061300710537 +ff97051400b9058f00c905140072042b0064050e00c902b0fef20323003704e300180323003704e3fffa06dd00ad051200b0 +061d004e05c400c905f3fffc05d8003d057b005c04330058055400a00554005c049f006804330071051700960554005d049f +006804150058051400ba025c00c903f000c903ac0014025d00c90b6000c90a6400c9093c007106af00c9064b00c903a700c1 +077300c9076400c9066100ba0579001004e7007b025cfffe0239ffe0064c007304e5007105db00b2051200ae05db00b20512 +00ae05db00b2051200ae05db00b2051200ae05db00b2051200ae04ec00710579001004e7007b0579001004e7007b07cb0008 +07db007b06330073051400710633007305140071053f00c904a2ffe9064c007304e50071064c007304e50071055400a0049f +00580239ffdb0b6000c90a6400c9093c0071063300730514007108e700c9057500c905fc00c9051200ba0579001004e7007b +07cb000807db007b064c006604e500480579001004e7007b0579001004e7007b050e00c904ec0071050e00c904ec0071025c +ffa70239ffc3025c00050239ffe3064c007304e50071064c007304e50071058f00c7034a0082058f00c9034a00ba05db00b2 +051200ae05db00b2051200ae05140087042b006f04e3fffa032300370504009c042c0047060400c90512fff005e200c906b4 +00710596007104e20071057b005c043300580579001004e7007b050e00c904ec0071064c007304e50071064c007304e50071 +064c007304e50071064c007304e5007104e3fffc04bc003d03cc008a06be00ba03d100370239ffdb07fc007107fc00710579 +fffd0596000c046600090475000a04e3ffb2042b006f0433005804d3005003d50050057d000a05db000c05790010050e00c9 +04ec0071025cff960239ffdb0640007305140071058f000a034a000e04e3fff604bc000b0000000000000000000000000000 +0000000000000000000000000000000000000000000004ec0071000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +049f005800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000028b00b200000000000000000000000000000000000000000000000000000000 +0000000000000000040000c1040000c100000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000040000c700000000040000ee0400014c040000b6 +040000f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000fda2000000000000000000000000000000000000fcc500000000000000000000fc5d000000000000fcbf0000fe1f0000 +0000000000000000000000000000000000000000000000000000000000000000fef000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000fd6a00000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000579001000000000000000000000000000000000 +0000000000000000050e00c90000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000051200ba0000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057d +00c9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000028b00b2000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000><0000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000ffb90000fcd70000fd730000fcb60000fd0c0000fccf0000fccf0000fcc70000fcc70000fd9a0000fce60000 +fc4e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +05fc00d500000000000000000578019200000000057801920578019305780193000000000000000005780176018b00000000 +0000000000000000003100310031003100310031003100310031003100310031003100310031003100310031003100310031 +0031003100310031003100310031003100310031003100ae00ae00f901380167016701ba01e8020c024302d602f802f8034c +039103910391041b049704cf0511051105ee05ee064f06ae06ae06ae06ae06ae06ae06d6076c076c07b70803086d086d08d1 +090d0935097209ea0a080a080a440a950a950a950acc0b7b0bb80bfa0bfa0d0c0d0c0df10e570e570e570e570e570e570e57 +0e570e570e570e570e570e570eb30eb30eb30eb30eb30eb30eb30ed80ed80ed80ed80ed80eff0eff0eff0f140f440f440f44 +0f440f440f440f440f440f440f440f440f440f440fe4104f105b106710731084109610a210ae10bf10d01135114c11581164 +1179119211a9120d12a912b512c112d812f312ff134213d513e713f91409141f143b145a15371543154f155b156c157d1589 +159515a615b7168f169b16a616b116c116d716ed171b17d517e017eb17fb1813181e186d1884189918ad18c318d318df18eb +18f7190319151921192d1939194a195619621975197d19db19e719f81a091a1a1a261a321a3e1a4a1a5b1a701a821a931a9f +1aab1abc1ac81ad41ae01af71b191b5c1ba61bb71bc81bd91bea1bfb1c0c1c181c241c3b1c611c721c831c941ca51cb11cbd +1d351d411d5d1d691d7a1d861d981da41dbd1dfa1e421e531e641e701e7c1e931ea81eb41eff1f4d1f621f721f871f971fa3 +1faf1ffe2092209e20a920b520c120d220e620f220fd21102122212e2139214c215f216a2175218a219b21dc2229223e224f +22662277228c229d22a922ba22c622d222de22ea22fb230c231d232d233e234a2355236123752381239523c12427248a2492 +24ec2532258525cd262d268a269226dc271a276d27d92807285e28ba28f9295429b92a432aaa2ad72b0f2b6d2bf62c252c99 +2cf92d602d682db92dc52dd12e242e792ec42f242f822fec308f309730e43130317831c5320b32173223327932bf331c3404 +3488350d357d35e4366b36a136da3723376937a237ec380c38183857385f386b38773883388f389b38a738b338bf38cb38db +38eb38fe3911391d392c393c394e395939653970397c39873993399e39aa39b239bd39c939d439e039ec39f83a613adb3af0 +3afb3b073b293b353b413b4d3b583b643b6f3b823b8e3b9a3ba63bb23bbd3c083c533c5f3c6b3c773c833c8f3c9b3ca73cb2 +3cbe3cca3cd63ce23cee3cfa3d063d123d1e3d2a3d363d423d4e3d5a3d663d723d7e3d8a3d963da23dae3dba3dc63dd23dde +3dea3df63e023e483e913e9d3ebf3ef83f4a3fd0404240b74133413f414b41574162416d417941844190419c41a841b341bf +41cb41d642004241427542a74317438943c0440b4452448844b1450d4538457a45bd462b468b469346c7471c476947b74817 +48744907494d497449a349a349a349a349a349a349a349a349a349a349f549f549f549f549f549f549f549f549f549f549f5 +49f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f5 +49f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f549f54a7e4a7e4a7e4a7e +4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e +4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a7e4a864a864a864a864a864a864a864a864a864a864ab34ae1 +4ae14ae14ae14ae14ae14ae14ae14ae14ae14ae14ae14ae14ae14ae14ae14ae14b264b264b5c4b8c4beb4c214c214c214c21 +4c214c214c214c214c214c214c214c214c214c214c214c214c214c214c214c214c214c214c214c214c214c434c434c434c43 +4c434c764c764c764cad4cad4cd24ce54ce54ce54ce54ce54ce54ce54ce54ce54d1f4d1f4d1f4d1f4d1f4d1f4d1f4d1f4d1f +4d1f4d1f4d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d31 +4d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d31 +4d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d31 +4d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d314d624d624d624d624d624d624d624da04da0 +4da04da04da04da04da04da04da04da04da04da04da04da04da04da04da04da04da04da04ddd4ddd4ddd4ddd4ddd4ddd4ddd +4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd +4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd +4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd +4ddd4ddd4ddd4ddd4ddd4ddd4ddd4ddd4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c +4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e1c4e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e394e39 +4e394e394e394e394e394e394e394e394e394e4b4eb04efd4f654fb85005505b507550c450f4511251285128512851285128 +5128512851285128512851285128512851285128512851285128512851285128512851285128512851285128512851285128 +51285128512851285128512851285128517051705170517d517d518a519751a451a451a451b151be00000001000017520354 +002b0068000c00020010009900080000041502160008000400000007005a0003000104090000013000000003000104090001 +0016013000030001040900020008014600030001040900030016013000030001040900040016013000030001040900050018 +014e0003000104090006001401660043006f0070007900720069006700680074002000280063002900200032003000300033 +002000620079002000420069007400730074007200650061006d002c00200049006e0063002e00200041006c006c00200052 +00690067006800740073002000520065007300650072007600650064002e000a0043006f0070007900720069006700680074 +0020002800630029002000320030003000360020006200790020005400610076006d006a006f006e00670020004200610068 +002e00200041006c006c0020005200690067006800740073002000520065007300650072007600650064002e000a00440065 +006a0061005600750020006300680061006e006700650073002000610072006500200069006e0020007000750062006c0069 +006300200064006f006d00610069006e000a00440065006a006100560075002000530061006e00730042006f006f006b0056 +0065007200730069006f006e00200032002e0033003500440065006a00610056007500530061006e00730002000000000000 +ff7e005a000000000000000000000000000000000000000017520000000100020003000400050006000700080009000a000b +000c000d000e000f0010001100120013001400150016001700180019001a001b001c001d001e001f00200021002200230024 +00250026002700280029002a002b002c002d002e002f0030003100320033003400350036003700380039003a003b003c003d +003e003f0040004100420043004400450046004700480049004a004b004c004d004e004f0050005100520053005400550056 +005700580059005a005b005c005d005e005f0060006100ac00a30084008500bd009600e80086008e008b009d00a900a40102 +008a00da0083009300f200f3008d0097008800c300de00f1009e00aa00f500f400f600a200ad00c900c700ae006200630090 +006400cb006500c800ca00cf00cc00cd00ce00e9006600d300d000d100af006700f0009100d600d400d5006800eb00ed0089 +006a0069006b006d006c006e00a0006f0071007000720073007500740076007700ea0078007a0079007b007d007c00b800a1 +007f007e0080008100ec00ee00ba01030104010501060107010800fd00fe0109010a010b010c00ff0100010d010e010f0101 +0110011101120113011401150116011701180119011a011b00f800f9011c011d011e011f0120012101220123012401250126 +012701280129012a012b00fa00d7012c012d012e012f0130013101320133013401350136013701380139013a00e200e3013b +013c013d013e013f014001410142014301440145014601470148014900b000b1014a014b014c014d014e014f015001510152 +015300fb00fc00e400e5015401550156015701580159015a015b015c015d015e015f01600161016201630164016501660167 +0168016900bb016a016b016c016d00e600e7016e016f0170017101720173017401750176017701780179017a017b017c017d +017e017f018000a6018101820183018401850186018701880189018a018b018c018d018e018f019001910192019301940195 +0196019701980199019a019b019c019d019e019f01a001a101a201a301a401a501a601a701a801a901aa01ab01ac01ad01ae +01af01b001b101b201b301b401b501b601b701b801b901ba01bb01bc01bd01be01bf01c001c101c201c301c401c501c601c7 +01c801c901ca01cb01cc01cd01ce01cf01d001d101d201d301d401d501d601d701d801d901da01db01dc01dd01de01df01e0 +01e101e201e301e401e501e601e701e801e901ea01eb01ec01ed01ee01ef01f001f101f201f301f401f501f601f701f801f9 +01fa01fb01fc01fd01fe01ff0200020102020203020402050206020702080209020a020b020c020d020e020f021002110212 +0213021402150216021702180219021a021b021c021d021e021f0220022102220223022402250226022702280229022a022b +022c022d022e022f0230023102320233023402350236023702380239023a023b023c023d023e023f02400241024202430244 +02450246024702480249024a024b024c024d024e024f0250025102520253025402550256025702580259025a025b025c025d +025e025f0260026102620263026402650266026702680269026a026b026c026d026e026f0270027102720273027402750276 +027702780279027a027b027c027d027e027f0280028102820283028402850286028702880289028a028b028c028d028e028f +0290029102920293029402950296029702980299029a029b029c029d029e029f02a002a102a202a302a402a502a602a702a8 +02a902aa02ab02ac02ad02ae02af02b002b102b202b300d800e102b402b502b602b702b802b902ba02bb02bc02bd02be02bf +02c002c102c202c300db00dc00dd00e000d900df02c402c502c602c702c802c902ca02cb02cc02cd02ce02cf02d002d102d2 +02d302d402d502d602d702d802d902da02db02dc02dd02de02df02e002e102e202e302e402e502e602e702e802e902ea02eb +02ec02ed02ee02ef02f002f102f202f302f402f502f602f702f802f902fa02fb02fc02fd02fe02ff03000301030203030304 +03050306030703080309030a030b030c030d030e030f0310031103120313031403150316031703180319031a031b031c031d +031e031f0320032103220323032403250326032703280329032a032b032c032d032e032f0330033103320333033403350336 +033703380339033a033b033c033d033e033f0340034103420343034403450346034703480349034a034b034c034d034e034f +0350035103520353035403550356035703580359035a035b035c035d035e035f0360009f0361036203630364036503660367 +03680369036a036b036c036d036e036f0370037103720373037403750376009b037703780379037a037b037c037d037e037f +0380038103820383038403850386038703880389038a038b038c038d038e038f039003910392039303940395039603970398 +0399039a039b039c039d039e039f03a003a103a203a303a403a503a603a703a803a903aa03ab03ac03ad03ae03af03b003b1 +03b203b303b403b503b603b703b803b903ba03bb03bc03bd03be03bf03c003c103c203c303c403c503c603c703c803c903ca +03cb03cc03cd03ce03cf03d003d103d203d303d403d503d603d703d803d903da03db03dc03dd03de03df03e003e103e203e3 +03e403e503e603e703e803e903ea03eb03ec03ed03ee03ef03f003f103f203f303f403f503f603f703f803f903fa03fb03fc +03fd03fe03ff0400040104020403040404050406040704080409040a040b040c040d040e040f041004110412041304140415 +0416041704180419041a041b041c041d041e041f0420042104220423042404250426042704280429042a042b042c042d042e +042f0430043104320433043404350436043704380439043a043b043c043d043e043f04400441044204430444044504460447 +04480449044a044b044c044d044e044f0450045104520453045404550456045704580459045a045b045c045d045e045f0460 +046104620463046404650466046704680469046a046b046c046d046e046f0470047104720473047404750476047704780479 +047a047b047c047d047e047f0480048104820483048404850486048704880489048a048b048c048d048e048f049004910492 +0493049404950496049704980499049a049b049c049d049e049f04a004a104a204a304a404a504a604a704a804a904aa04ab +04ac04ad04ae04af04b004b104b204b304b404b504b604b704b804b904ba04bb04bc04bd04be04bf04c004c104c204c304c4 +04c504c604c704c804c904ca04cb04cc04cd04ce04cf04d004d104d204d304d404d504d604d704d804d904da04db04dc04dd +04de04df04e004e104e204e304e404e504e604e704e804e904ea04eb04ec04ed04ee04ef04f004f104f204f304f404f504f6 +04f704f804f904fa04fb04fc04fd04fe04ff0500050105020503050405050506050705080509050a050b050c050d050e050f +0510051105120513051405150516051705180519051a051b051c051d051e051f052005210522052305240525052605270528 +0529052a052b052c052d052e052f0530053105320533053405350536053705380539053a053b053c053d053e053f05400541 +05420543054405450546054705480549054a054b054c054d054e054f0550055105520553055405550556055705580559055a +055b055c055d055e055f0560056105620563056405650566056705680569056a056b056c056d056e056f0570057105720573 +057405750576057705780579057a057b057c057d057e057f0580058105820583058405850586058705880589058a058b058c +058d058e058f0590059105920593059405950596059705980599059a059b059c059d059e059f05a005a105a205a305a405a5 +05a605a705a805a905aa05ab05ac05ad05ae05af05b005b105b205b305b405b505b605b705b805b905ba05bb05bc05bd05be +05bf05c005c105c205c305c405c505c605c705c805c905ca05cb05cc05cd05ce05cf05d005d105d205d305d405d505d605d7 +05d805d905da05db05dc05dd05de05df05e005e105e205e305e405e505e605e705e805e905ea05eb05ec05ed05ee05ef05f0 +05f105f205f305f405f505f605f705f805f905fa05fb05fc05fd05fe05ff0600060106020603060406050606060706080609 +060a060b060c060d060e060f0610061106120613061406150616061706180619061a061b061c061d061e061f062006210622 +0623062406250626062706280629062a062b062c062d062e062f0630063106320633063406350636063706380639063a063b +063c063d063e063f0640064106420643064406450646064706480649064a064b064c064d064e064f06500651065206530654 +06550656065706580659065a065b065c065d065e065f0660066106620663066406650666066706680669066a066b066c066d +066e066f0670067106720673067406750676067706780679067a067b067c067d067e067f0680068106820683068406850686 +068706880689068a068b068c068d068e068f0690069106920693069406950696069706980699069a069b069c069d069e069f +06a006a106a206a306a406a506a606a706a806a906aa06ab06ac06ad06ae06af06b006b106b206b306b406b506b606b706b8 +06b906ba06bb06bc06bd06be06bf06c006c106c206c306c406c506c606c706c806c906ca06cb06cc06cd06ce06cf06d006d1 +06d206d306d406d506d606d706d806d906da06db06dc06dd06de06df06e006e106e206e306e406e506e606e706e806e906ea +06eb06ec06ed06ee06ef06f006f106f206f306f406f506f606f706f806f906fa06fb06fc06fd06fe06ff0700070107020703 +070407050706070707080709070a070b070c070d070e070f0710071107120713071407150716071707180719071a071b071c +071d071e071f0720072107220723072407250726072707280729072a072b072c072d072e072f073007310732073307340735 +0736073707380739073a073b073c073d073e073f0740074107420743074407450746074707480749074a074b074c074d074e +074f0750075107520753075407550756075707580759075a075b075c075d075e075f07600761076207630764076507660767 +07680769076a076b076c076d076e076f0770077107720773077407750776077707780779077a077b077c077d077e077f0780 +078107820783078407850786078707880789078a078b078c078d078e078f0790079107920793079407950796079707980799 +079a079b079c079d079e079f07a007a107a207a307a407a507a607a707a807a907aa07ab07ac07ad07ae07af07b007b107b2 +07b307b407b507b607b707b807b907ba07bb07bc07bd07be07bf07c007c107c207c307c407c507c607c707c807c907ca07cb +07cc07cd07ce07cf07d007d107d207d307d407d507d607d707d807d907da07db07dc07dd07de07df07e007e107e207e307e4 +07e507e607e707e807e907ea07eb07ec07ed07ee07ef07f007f107f207f307f407f507f607f707f807f907fa07fb07fc07fd +07fe07ff0800080108020803080408050806080708080809080a080b080c080d080e080f0810081108120813081408150816 +081708180819081a081b081c081d081e081f0820082108220823082408250826082708280829082a082b082c082d082e082f +0830083108320833083408350836083708380839083a083b083c083d083e083f084008410842084308440845084608470848 +0849084a084b084c084d084e084f0850085108520853085408550856085708580859085a085b085c085d085e085f08600861 +08620863086408650866086708680869086a086b086c086d086e086f0870087108720873087408750876087708780879087a +087b087c087d087e087f0880088108820883088408850886088708880889088a088b088c088d088e088f0890089108920893 +089408950896089708980899089a089b089c089d089e089f08a008a108a208a308a408a508a608a708a808a908aa08ab08ac +08ad08ae08af08b008b108b208b308b408b508b608b708b808b908ba08bb08bc08bd08be08bf08c008c108c208c308c408c5 +08c608c708c808c908ca08cb08cc08cd08ce08cf08d008d108d208d308d408d508d608d708d808d908da08db08dc08dd08de +08df08e008e108e208e308e408e508e608e708e808e908ea08eb08ec08ed08ee08ef08f008f108f208f308f408f508f608f7 +08f808f908fa08fb08fc08fd08fe08ff0900090109020903090409050906090709080909090a090b090c090d090e090f0910 +091109120913091409150916091709180919091a091b091c091d091e091f0920092109220923092409250926092709280929 +092a092b092c092d092e092f0930093109320933093409350936093709380939093a093b093c093d093e093f094009410942 +0943094409450946094709480949094a094b094c094d094e094f0950095109520953095409550956095709580959095a095b +095c095d095e095f0960096109620963096409650966096709680969096a096b096c096d096e096f09700971097209730974 +09750976097709780979097a097b097c097d097e097f0980098109820983098409850986098709880989098a098b098c098d +098e098f0990099109920993099409950996099709980999099a099b099c099d099e099f09a009a109a209a309a409a509a6 +09a709a809a909aa09ab09ac09ad09ae09af09b009b109b209b309b409b509b609b709b809b909ba09bb09bc09bd09be09bf +09c009c109c209c309c409c509c609c709c809c909ca09cb09cc09cd09ce09cf09d009d109d209d309d409d509d609d709d8 +09d909da09db09dc09dd09de09df09e009e109e209e309e409e509e609e709e809e909ea09eb09ec09ed09ee09ef09f009f1 +09f209f309f409f509f609f709f809f909fa09fb09fc09fd09fe09ff0a000a010a020a030a040a050a060a070a080a090a0a +0a0b0a0c0a0d0a0e0a0f0a100a110a120a130a140a150a160a170a180a190a1a0a1b0a1c0a1d0a1e0a1f0a200a210a220a23 +0a240a250a260a270a280a290a2a0a2b0a2c0a2d0a2e0a2f0a300a310a320a330a340a350a360a370a380a390a3a0a3b0a3c +0a3d0a3e0a3f0a400a410a420a430a440a450a460a470a480a490a4a0a4b0a4c0a4d0a4e0a4f0a500a510a520a530a540a55 +0a560a570a580a590a5a0a5b0a5c0a5d0a5e0a5f0a600a610a620a630a640a650a660a670a680a690a6a0a6b0a6c0a6d0a6e +0a6f0a700a710a720a730a740a750a760a770a780a790a7a0a7b0a7c0a7d0a7e0a7f0a800a810a820a830a840a850a860a87 +0a880a890a8a0a8b0a8c0a8d0a8e0a8f0a900a910a920a930a940a950a960a970a980a990a9a0a9b0a9c0a9d0a9e0a9f0aa0 +0aa10aa20aa30aa40aa50aa60aa70aa80aa90aaa0aab0aac0aad0aae0aaf0ab00ab10ab20ab30ab40ab50ab60ab70ab80ab9 +0aba0abb0abc0abd0abe0abf0ac00ac10ac20ac30ac40ac50ac60ac70ac80ac90aca0acb0acc0acd0ace0acf0ad00ad10ad2 +0ad30ad40ad50ad60ad70ad80ad90ada0adb0adc0add0ade0adf0ae00ae10ae20ae30ae40ae50ae60ae70ae80ae90aea0aeb +0aec0aed0aee0aef0af00af10af20af30af40af50af60af70af80af90afa0afb0afc0afd0afe0aff0b000b010b020b030b04 +0b050b060b070b080b090b0a0b0b0b0c0b0d0b0e0b0f0b100b110b120b130b140b150b1600b200b30b170b180b1900b600b7 +00c40b1a00b400b500c50b1b008200c200870b1c0b1d0b1e00ab0b1f0b200b210b220b230b240b250b260b2700c60b280b29 +0b2a0b2b0b2c0b2d0b2e0b2f00be00bf0b300b310b320b330b340b350b360b370b3800bc0b390b3a0b3b0b3c0b3d0b3e0b3f +0b400b410b420b430b440b450b460b470b480b490b4a0b4b0b4c0b4d0b4e0b4f0b500b510b520b530b540b550b560b570b58 +0b590b5a0b5b0b5c0b5d0b5e0b5f0b600b610b620b630b640b650b660b670b680b690b6a0b6b0b6c0b6d0b6e0b6f0b700b71 +0b720b730b740b750b760b770b780b790b7a0b7b0b7c0b7d0b7e0b7f0b800b810b820b830b840b850b860b870b880b890b8a +0b8b00f70b8c0b8d0b8e0b8f0b900b910b920b930b940b950b960b970b980b990b9a0b9b0b9c0b9d0b9e0b9f0ba00ba10ba2 +0ba30ba40ba50ba60ba70ba80ba90baa0bab0bac0bad0bae0baf0bb00bb10bb20bb30bb40bb50bb60bb70bb80bb90bba0bbb +0bbc0bbd0bbe0bbf0bc00bc10bc20bc30bc40bc50bc60bc70bc80bc9008c0bca0bcb0bcc0bcd0bce0bcf0bd00bd10bd20bd3 +0bd40bd50bd60bd70bd80bd90bda0bdb0bdc0bdd0bde0bdf0be00be10be20be30be40be50be60be70be80be90bea0beb0bec +0bed0bee0bef0bf00bf10bf20bf30bf40bf50bf60bf70bf80bf90bfa0bfb0bfc0bfd0bfe0bff0c000c010c020c030c040c05 +0c060c070c080c090c0a0c0b0c0c0c0d0c0e0c0f0c100c110c120c130c140c150c160c170c180c190c1a0c1b0c1c0c1d0c1e +0c1f0c200c210c220c230c240c250c260c270c280c290c2a0c2b0c2c0c2d0c2e0c2f0c300c310c320c330c340c350c360c37 +0c380c390c3a0c3b0c3c0c3d0c3e0c3f0c400c410c420c430c440c450c460c470c480c490c4a0c4b0c4c0c4d0c4e0c4f0c50 +0c510c520c530c540c550c560c570c580c590c5a0c5b0c5c0c5d0c5e0c5f0c600c610c620c630c640c650c660c670c680c69 +0c6a0c6b0c6c0c6d0c6e0c6f0c700c710c720c730c740c750c760c770c780c790c7a0c7b0c7c0c7d0c7e0c7f0c800c810c82 +0c830c840c850c860c870c880c890c8a0c8b0c8c0c8d0c8e0c8f0c900c910c920c930c940c950c960c970c980c990c9a0c9b +00980c9c0c9d0c9e00a80c9f0ca00ca10ca20ca30ca40ca50ca6009a0ca7009900ef0ca80ca90caa0cab0cac0cad0cae00a5 +0caf0cb00cb100920cb20cb30cb40cb50cb60cb70cb80cb90cba0cbb0cbc0cbd009c0cbe0cbf0cc00cc10cc20cc30cc40cc5 +0cc60cc70cc80cc90cca0ccb0ccc0ccd0cce0ccf0cd00cd10cd20cd30cd40cd50cd60cd70cd80cd900a70cda0cdb0cdc0cdd +0cde0cdf0ce00ce10ce20ce30ce40ce50ce60ce70ce80ce90cea0ceb0cec0ced0cee0cef0cf0008f0cf10cf20cf300940095 +0cf40cf50cf60cf70cf80cf90cfa0cfb0cfc0cfd0cfe0cff0d000d010d020d030d040d050d060d070d080d090d0a0d0b0d0c +0d0d0d0e0d0f0d100d110d120d130d140d150d160d170d180d190d1a0d1b0d1c0d1d0d1e0d1f0d200d210d220d230d240d25 +0d260d270d280d290d2a0d2b0d2c0d2d0d2e0d2f0d300d310d320d330d340d350d360d370d380d390d3a0d3b0d3c0d3d0d3e +0d3f0d400d410d420d430d440d450d460d470d480d490d4a0d4b0d4c0d4d0d4e0d4f0d500d510d520d530d540d550d560d57 +0d580d590d5a0d5b0d5c0d5d0d5e0d5f0d600d610d620d630d640d650d660d670d680d690d6a0d6b0d6c0d6d0d6e0d6f0d70 +0d710d720d730d740d750d760d770d780d790d7a0d7b0d7c0d7d0d7e0d7f0d800d810d820d830d840d850d860d870d880d89 +0d8a0d8b0d8c0d8d0d8e0d8f0d900d910d920d930d940d950d960d970d980d990d9a0d9b0d9c0d9d0d9e0d9f0da00da10da2 +0da30da40da50da60da70da80da90daa0dab0dac0dad0dae0daf0db00db10db20db30db40db50db60db70db80db90dba0dbb +0dbc0dbd0dbe0dbf0dc00dc10dc20dc30dc40dc50dc60dc70dc80dc90dca0dcb0dcc0dcd0dce0dcf0dd00dd10dd20dd30dd4 +0dd50dd60dd70dd80dd90dda0ddb0ddc0ddd0dde0ddf0de00de10de20de30de40de50de60de70de80de90dea0deb0dec0ded +0dee0def0df00df10df20df30df40df50df60df70df80df90dfa0dfb0dfc0dfd0dfe0dff0e000e010e020e030e040e050e06 +0e070e080e090e0a0e0b0e0c0e0d0e0e0e0f0e100e110e120e130e140e150e160e170e180e190e1a0e1b0e1c0e1d0e1e0e1f +0e200e210e220e230e240e250e260e270e280e290e2a0e2b0e2c0e2d0e2e0e2f0e300e310e320e330e340e350e360e370e38 +0e390e3a0e3b0e3c0e3d0e3e0e3f0e400e410e420e430e440e450e460e470e480e490e4a0e4b0e4c0e4d0e4e0e4f0e500e51 +0e520e530e540e550e560e570e580e590e5a0e5b0e5c0e5d0e5e0e5f0e600e610e620e630e640e650e660e670e680e690e6a +0e6b0e6c0e6d0e6e0e6f0e700e710e720e730e740e750e760e770e780e790e7a0e7b0e7c0e7d0e7e0e7f0e800e810e820e83 +0e840e850e860e870e880e890e8a0e8b0e8c0e8d0e8e0e8f0e900e910e920e930e940e950e960e970e980e990e9a0e9b0e9c +0e9d0e9e0e9f0ea00ea10ea20ea30ea400b90ea50ea60ea70ea80ea90eaa0eab0eac0ead0eae0eaf0eb00eb10eb20eb30eb4 +0eb50eb60eb70eb80eb90eba0ebb0ebc0ebd0ebe0ebf0ec00ec10ec20ec30ec40ec50ec60ec70ec80ec90eca0ecb0ecc0ecd +0ece0ecf0ed00ed10ed20ed30ed40ed50ed60ed70ed80ed90eda0edb0edc0edd0ede0edf0ee00ee10ee20ee30ee40ee50ee6 +0ee70ee80ee90eea0eeb0eec0eed0eee0eef0ef00ef10ef20ef30ef40ef50ef60ef70ef80ef90efa0efb0efc0efd0efe0eff +0f000f010f020f030f040f050f060f070f080f090f0a0f0b0f0c0f0d0f0e0f0f0f100f110f120f130f140f150f160f170f18 +0f190f1a0f1b0f1c0f1d0f1e0f1f0f200f210f220f230f240f250f260f270f280f290f2a0f2b0f2c0f2d0f2e0f2f0f300f31 +0f320f330f340f350f360f370f380f390f3a0f3b0f3c0f3d0f3e0f3f0f400f410f420f430f440f450f460f470f480f490f4a +0f4b0f4c0f4d0f4e0f4f0f500f510f520f530f540f550f560f570f580f590f5a0f5b0f5c0f5d0f5e0f5f0f600f610f620f63 +0f640f650f660f670f680f690f6a0f6b0f6c0f6d0f6e0f6f0f700f710f720f730f740f750f760f770f780f790f7a0f7b0f7c +0f7d0f7e0f7f0f800f810f820f830f840f850f860f870f880f890f8a0f8b0f8c0f8d0f8e0f8f0f900f910f920f930f940f95 +0f960f970f980f990f9a0f9b0f9c0f9d0f9e0f9f0fa00fa10fa20fa30fa40fa50fa60fa70fa80fa90faa0fab0fac0fad0fae +0faf0fb00fb10fb20fb30fb40fb50fb60fb70fb80fb90fba0fbb0fbc0fbd0fbe0fbf0fc00fc10fc20fc30fc40fc50fc60fc7 +0fc80fc90fca0fcb0fcc0fcd0fce0fcf0fd00fd10fd20fd30fd40fd50fd60fd70fd80fd90fda0fdb0fdc0fdd0fde0fdf0fe0 +0fe10fe20fe30fe40fe50fe60fe70fe80fe90fea0feb0fec0fed0fee0fef0ff00ff10ff20ff30ff40ff50ff60ff70ff80ff9 +0ffa0ffb0ffc0ffd0ffe0fff1000100110021003100410051006100710081009100a100b100c100d100e100f101010111012 +1013101410151016101710181019101a101b101c101d101e101f1020102110221023102410251026102710281029102a102b +102c102d102e102f1030103110321033103410351036103710381039103a103b103c103d103e103f10401041104210431044 +10451046104710481049104a104b104c104d104e104f1050105110521053105410551056105710581059105a105b105c105d +105e105f1060106110621063106410651066106710681069106a106b106c106d106e106f1070107110721073107410751076 +107710781079107a107b107c107d107e107f1080108110821083108410851086108710881089108a108b108c108d108e108f +1090109110921093109410951096109710981099109a109b109c109d109e109f10a010a110a210a310a410a510a610a710a8 +10a910aa10ab10ac10ad10ae10af10b010b110b210b310b410b510b610b710b810b910ba10bb10bc10bd10be10bf10c010c1 +10c210c310c410c510c610c710c810c910ca10cb10cc10cd10ce10cf10d010d110d210d310d410d510d610d710d810d910da +10db10dc10dd10de10df10e010e110e210e310e410e510e610e710e810e910ea10eb10ec10ed10ee10ef10f010f110f210f3 +10f410f510f610f710f810f910fa10fb10fc10fd10fe10ff1100110111021103110411051106110711081109110a110b110c +110d110e110f1110111111121113111411151116111711181119111a111b111c111d111e111f112011211122112311241125 +1126112711281129112a112b112c112d112e112f1130113111321133113411351136113711381139113a113b113c113d113e +113f1140114111421143114411451146114711481149114a114b114c114d114e114f11501151115211531154115511561157 +11581159115a115b115c115d115e115f1160116111621163116411651166116711681169116a116b116c116d116e116f1170 +117111721173117411751176117711781179117a117b117c117d117e117f1180118111821183118411851186118711881189 +118a118b118c118d118e118f1190119111921193119411951196119711981199119a119b119c119d119e119f11a011a111a2 +11a311a411a511a611a711a811a911aa11ab11ac11ad11ae11af11b011b111b211b311b411b511b611b711b811b911ba11bb +11bc11bd11be11bf11c011c111c211c311c411c511c611c711c811c911ca11cb11cc11cd11ce11cf11d011d111d211d311d4 +11d511d611d711d811d911da11db11dc11dd11de11df11e011e111e211e311e411e511e611e711e811e911ea11eb11ec11ed +11ee11ef11f011f111f211f311f411f511f611f711f811f911fa11fb11fc11fd11fe11ff1200120112021203120412051206 +120712081209120a120b120c120d120e120f1210121112121213121412151216121712181219121a121b121c121d121e121f +1220122112221223122412251226122712281229122a122b122c122d122e122f123012311232123312341235123612371238 +1239123a123b123c123d123e123f1240124112421243124412451246124712481249124a124b124c124d124e124f12501251 +12521253125412551256125712581259125a125b125c125d125e125f1260126112621263126412651266126712681269126a +126b126c126d126e126f1270127112721273127412751276127712781279127a127b127c127d127e127f1280128112821283 +128412851286128712881289128a128b128c128d128e128f1290129112921293129412951296129712981299129a129b129c +129d129e129f12a012a112a212a312a412a512a612a712a812a912aa12ab12ac12ad12ae12af12b012b112b212b312b412b5 +12b612b712b812b912ba12bb12bc12bd12be12bf12c012c112c212c312c412c512c612c712c812c912ca12cb12cc12cd12ce +12cf12d012d112d212d312d412d512d612d712d812d912da12db12dc12dd12de12df12e012e112e212e312e412e512e612e7 +12e812e912ea12eb12ec12ed12ee12ef12f012f112f212f312f412f512f612f712f812f912fa12fb12fc12fd12fe12ff1300 +130113021303130413051306130713081309130a130b130c130d130e130f1310131113121313131413151316131713181319 +131a131b131c131d131e131f1320132113221323132413251326132713281329132a132b132c132d132e132f133013311332 +1333133413351336133713381339133a133b133c133d133e133f1340134113421343134413451346134713481349134a134b +134c134d134e134f1350135113521353135413551356135713581359135a135b135c135d135e135f13601361136213631364 +13651366136713681369136a136b136c136d136e136f1370137113721373137413751376137713781379137a137b137c137d +137e137f1380138113821383138413851386138713881389138a138b138c138d138e138f1390139113921393139413951396 +139713981399139a139b139c139d139e139f13a013a113a213a313a413a513a613a713a813a913aa13ab13ac13ad13ae13af +13b013b100c000c113b213b313b413b513b613b713b813b913ba13bb13bc13bd13be13bf13c013c113c213c313c413c513c6 +13c713c813c913ca13cb13cc13cd13ce13cf13d013d113d213d313d413d513d613d713d813d913da13db13dc13dd13de13df +13e013e113e213e313e413e513e613e713e813e913ea13eb13ec13ed13ee13ef13f013f113f213f313f413f513f613f713f8 +13f913fa13fb13fc13fd13fe13ff1400140114021403140414051406140714081409140a140b140c140d140e140f14101411 +14121413141414151416141714181419141a141b141c141d141e141f1420142114221423142414251426142714281429142a +142b142c142d142e142f1430143114321433143414351436143714381439143a143b143c143d143e143f1440144114421443 +144414451446144714481449144a144b144c144d144e144f1450145114521453145414551456145714581459145a145b145c +145d145e145f1460146114621463146414651466146714681469146a146b146c146d146e146f147014711472147314741475 +1476147714781479147a147b147c147d147e147f1480148114821483148414851486148714881489148a148b148c148d148e +148f1490149114921493149414951496149714981499149a149b149c149d149e149f14a014a114a214a314a414a514a614a7 +14a814a914aa14ab14ac14ad14ae14af14b014b114b214b314b414b514b614b714b814b914ba14bb14bc14bd14be14bf14c0 +14c114c214c314c414c514c614c714c814c914ca14cb14cc14cd14ce14cf14d014d114d214d314d414d514d614d714d814d9 +14da14db14dc14dd14de14df14e014e114e214e314e414e514e614e714e814e914ea14eb14ec14ed14ee14ef14f014f114f2 +14f314f414f514f614f714f814f914fa14fb14fc14fd14fe14ff1500150115021503150415051506150715081509150a150b +150c150d150e150f1510151115121513151415151516151715181519151a151b151c151d151e151f15201521152215231524 +15251526152715281529152a152b152c152d152e152f1530153115321533153415351536153715381539153a153b153c153d +153e153f1540154115421543154415451546154715481549154a154b154c154d154e154f1550155115521553155415551556 +155715581559155a155b155c155d155e155f1560156115621563156415651566156715681569156a156b156c156d156e156f +1570157115721573157415751576157715781579157a157b157c157d157e157f158015811582158315841585158615871588 +1589158a158b158c158d158e158f1590159115921593159415951596159715981599159a159b159c159d159e159f15a015a1 +15a215a315a415a515a615a715a815a915aa15ab15ac15ad15ae15af15b015b115b215b315b415b515b615b715b815b915ba +15bb15bc15bd15be15bf15c015c115c215c315c415c515c615c715c815c915ca15cb15cc15cd15ce15cf15d015d115d215d3 +15d415d515d615d715d815d915da15db15dc15dd15de15df15e015e115e215e315e415e515e615e715e815e915ea15eb15ec +15ed15ee15ef15f015f115f215f315f415f515f615f715f815f915fa15fb15fc15fd15fe15ff160016011602160316041605 +1606160716081609160a160b160c160d160e160f1610161116121613161416151616161716181619161a161b161c161d161e +161f1620162116221623162416251626162716281629162a162b162c162d162e162f16301631163216331634163516361637 +16381639163a163b163c163d163e163f1640164116421643164416451646164716481649164a164b164c164d164e164f1650 +165116521653165416551656165716581659165a165b165c165d165e165f1660166116621663166416651666166716681669 +166a166b166c166d166e166f1670167116721673167416751676167716781679167a167b167c167d167e167f168016811682 +1683168416851686168716881689168a168b168c168d168e168f1690169116921693169416951696169716981699169a169b +169c169d169e169f16a016a116a216a316a416a516a616a716a816a916aa16ab16ac16ad16ae16af16b016b116b216b316b4 +16b516b616b716b816b916ba16bb16bc16bd16be16bf16c016c116c216c316c416c516c616c716c816c916ca16cb16cc16cd +16ce16cf16d016d116d216d316d416d516d616d716d816d916da16db16dc16dd16de16df16e016e116e216e316e416e516e6 +16e716e816e916ea16eb16ec16ed16ee16ef16f016f116f216f316f416f516f616f716f816f916fa16fb16fc16fd16fe16ff +1700170117021703170417051706170717081709170a170b170c170d170e170f171017111712171317141715171617171718 +1719171a171b171c171d171e171f1720172117221723172417251726172717281729172a172b172c172d172e172f17301731 +17321733173417351736173717381739173a173b173c173d173e173f1740174117421743174417451746174717481749174a +174b174c174d174e174f1750175117520973667468797068656e07416d6163726f6e07616d6163726f6e0641627265766506 +61627265766507416f676f6e656b07616f676f6e656b0b4363697263756d666c65780b6363697263756d666c65780a43646f +74616363656e740a63646f74616363656e7406446361726f6e06646361726f6e064463726f617407456d6163726f6e07656d +6163726f6e06456272657665066562726576650a45646f74616363656e740a65646f74616363656e7407456f676f6e656b07 +656f676f6e656b06456361726f6e06656361726f6e0b4763697263756d666c65780b6763697263756d666c65780a47646f74 +616363656e740a67646f74616363656e740c47636f6d6d61616363656e740c67636f6d6d61616363656e740b486369726375 +6d666c65780b6863697263756d666c657804486261720468626172064974696c6465066974696c646507496d6163726f6e07 +696d6163726f6e064962726576650669627265766507496f676f6e656b07696f676f6e656b02494a02696a0b4a6369726375 +6d666c65780b6a63697263756d666c65780c4b636f6d6d61616363656e740c6b636f6d6d61616363656e740c6b677265656e +6c616e646963064c6163757465066c61637574650c4c636f6d6d61616363656e740c6c636f6d6d61616363656e74064c6361 +726f6e066c6361726f6e044c646f74046c646f74064e6163757465066e61637574650c4e636f6d6d61616363656e740c6e63 +6f6d6d61616363656e74064e6361726f6e066e6361726f6e0b6e61706f7374726f70686503456e6703656e67074f6d616372 +6f6e076f6d6163726f6e064f6272657665066f62726576650d4f68756e676172756d6c6175740d6f68756e676172756d6c61 +757406526163757465067261637574650c52636f6d6d61616363656e740c72636f6d6d61616363656e7406526361726f6e06 +726361726f6e06536163757465067361637574650b5363697263756d666c65780b7363697263756d666c65780c54636f6d6d +61616363656e740c74636f6d6d61616363656e7406546361726f6e06746361726f6e04546261720474626172065574696c64 +65067574696c646507556d6163726f6e07756d6163726f6e0655627265766506756272657665055572696e67057572696e67 +0d5568756e676172756d6c6175740d7568756e676172756d6c61757407556f676f6e656b07756f676f6e656b0b5763697263 +756d666c65780b7763697263756d666c65780b5963697263756d666c65780b7963697263756d666c6578065a616375746506 +7a61637574650a5a646f74616363656e740a7a646f74616363656e74056c6f6e677307756e693031383007756e6930313831 +07756e693031383207756e693031383307756e693031383407756e693031383507756e693031383607756e69303138370775 +6e693031383807756e693031383907756e693031384107756e693031384207756e693031384307756e693031384407756e69 +3031384507756e693031384607756e693031393007756e693031393107756e693031393307756e693031393407756e693031 +393507756e693031393607756e693031393707756e693031393807756e693031393907756e693031394107756e6930313942 +07756e693031394307756e693031394407756e693031394507756e6930313946054f686f726e056f686f726e07756e693031 +413207756e693031413307756e693031413407756e693031413507756e693031413607756e693031413707756e6930314138 +07756e693031413907756e693031414107756e693031414207756e693031414307756e693031414407756e69303141450555 +686f726e0575686f726e07756e693031423107756e693031423207756e693031423307756e693031423407756e6930314235 +07756e693031423607756e693031423707756e693031423807756e693031423907756e693031424107756e69303142420775 +6e693031424307756e693031424407756e693031424507756e693031424607756e693031433007756e693031433107756e69 +3031433207756e693031433307756e693031433407756e693031433507756e693031433607756e693031433707756e693031 +433807756e693031433907756e693031434107756e693031434207756e693031434307756e693031434407756e6930314345 +07756e693031434607756e693031443007756e693031443107756e693031443207756e693031443307756e69303144340775 +6e693031443507756e693031443607756e693031443707756e693031443807756e693031443907756e693031444107756e69 +3031444207756e693031444307756e693031444407756e693031444507756e693031444607756e693031453007756e693031 +453107756e693031453207756e693031453307756e693031453407756e693031453506476361726f6e06676361726f6e0775 +6e693031453807756e693031453907756e693031454107756e693031454207756e693031454307756e693031454407756e69 +3031454507756e693031454607756e693031463007756e693031463107756e693031463207756e693031463307756e693031 +463407756e693031463507756e693031463607756e693031463707756e693031463807756e69303146390a4172696e676163 +7574650a6172696e676163757465074145616375746507616561637574650b4f736c61736861637574650b6f736c61736861 +6375746507756e693032303007756e693032303107756e693032303207756e693032303307756e693032303407756e693032 +303507756e693032303607756e693032303707756e693032303807756e693032303907756e693032304107756e6930323042 +07756e693032304307756e693032304407756e693032304507756e693032304607756e693032313007756e69303231310775 +6e693032313207756e693032313307756e693032313407756e693032313507756e693032313607756e69303231370c53636f +6d6d61616363656e740c73636f6d6d61616363656e7407756e693032314107756e693032314207756e693032314307756e69 +3032314407756e693032314507756e693032314607756e693032323007756e693032323107756e693032323207756e693032 +323307756e693032323407756e693032323507756e693032323607756e693032323707756e693032323807756e6930323239 +07756e693032324107756e693032324207756e693032324307756e693032324407756e693032324507756e69303232460775 +6e693032333007756e693032333107756e693032333207756e693032333307756e693032333407756e693032333507756e69 +3032333608646f746c6573736a07756e693032333807756e693032333907756e693032334107756e693032334207756e6930 +32334307756e693032334407756e693032334507756e693032334607756e693032343007756e693032343107756e69303234 +3207756e693032343307756e693032343407756e693032343507756e693032343607756e693032343707756e693032343807 +756e693032343907756e693032344107756e693032344207756e693032344307756e693032344407756e693032344507756e +693032344607756e693032353007756e693032353107756e693032353207756e693032353307756e693032353407756e6930 +32353507756e693032353607756e693032353707756e693032353807756e693032353907756e693032354107756e69303235 +4207756e693032354307756e693032354407756e693032354507756e693032354607756e693032363007756e693032363107 +756e693032363207756e693032363307756e693032363407756e693032363507756e693032363607756e693032363707756e +693032363807756e693032363907756e693032364107756e693032364207756e693032364307756e693032364407756e6930 +32364507756e693032364607756e693032373007756e693032373107756e693032373207756e693032373307756e69303237 +3407756e693032373507756e693032373607756e693032373707756e693032373807756e693032373907756e693032374107 +756e693032374207756e693032374307756e693032374407756e693032374507756e693032374607756e693032383007756e +693032383107756e693032383207756e693032383307756e693032383407756e693032383507756e693032383607756e6930 +32383707756e693032383807756e693032383907756e693032384107756e693032384207756e693032384307756e69303238 +4407756e693032384507756e693032384607756e693032393007756e693032393107756e693032393207756e693032393307 +756e693032393407756e693032393507756e693032393607756e693032393707756e693032393807756e693032393907756e +693032394107756e693032394207756e693032394307756e693032394407756e693032394507756e693032394607756e6930 +32413007756e693032413107756e693032413207756e693032413307756e693032413407756e693032413507756e69303241 +3607756e693032413707756e693032413807756e693032413907756e693032414107756e693032414207756e693032414307 +756e693032414407756e693032414507756e693032414607756e693032423007756e693032423107756e693032423207756e +693032423307756e693032423407756e693032423507756e693032423607756e693032423707756e693032423807756e6930 +32423907756e693032424107756e693032424207756e693032424307756e693032424407756e693032424507756e69303242 +4607756e693032433007756e693032433107756e693032433207756e693032433307756e693032433407756e693032433507 +756e693032433807756e693032433907756e693032434107756e693032434207756e693032434307756e693032434407756e +693032434507756e693032434607756e693032443007756e693032443107756e693032443207756e693032443307756e6930 +32443407756e693032443507756e693032443607756e693032443707756e693032444507756e693032444607756e69303245 +3007756e693032453107756e693032453207756e693032453307756e693032453407756e693032453507756e693032453607 +756e693032453707756e693032453807756e693032453907756e693032454307756e693032454407756e693032454507756e +693032463307756e6930324637096772617665636f6d62096163757465636f6d6207756e69303330320974696c6465636f6d +6207756e693033303407756e693033303507756e693033303607756e693033303707756e69303330380d686f6f6b61626f76 +65636f6d6207756e693033304107756e693033304207756e693033304307756e693033304407756e693033304507756e6930 +33304607756e693033313007756e693033313107756e693033313207756e693033313307756e693033313407756e69303331 +3507756e693033313607756e693033313707756e693033313807756e693033313907756e693033314107756e693033314207 +756e693033314307756e693033314407756e693033314507756e693033314607756e693033323007756e693033323107756e +69303332320c646f7462656c6f77636f6d6207756e693033323407756e693033323507756e693033323607756e6930333237 +07756e693033323807756e693033323907756e693033324107756e693033324207756e693033324307756e69303332440775 +6e693033324507756e693033324607756e693033333007756e693033333107756e693033333207756e693033333307756e69 +3033333407756e693033333507756e693033333607756e693033333707756e693033333807756e693033333907756e693033 +334107756e693033334207756e693033334307756e693033334407756e693033334507756e693033334607756e6930333430 +07756e693033343107756e693033343207756e693033343307756e693033343407756e693033343507756e69303334360775 +6e693033343707756e693033343807756e693033343907756e693033344107756e693033344207756e693033344307756e69 +3033344407756e693033344507756e693033344607756e693033353107756e693033353207756e693033353307756e693033 +353707756e693033353807756e693033354107756e693033354307756e693033354407756e693033354507756e6930333546 +07756e693033363007756e693033363107756e693033363207756e693033373007756e693033373107756e69303337320775 +6e693033373307756e693033373407756e693033373507756e693033373607756e693033373707756e693033374107756e69 +3033374207756e693033374307756e693033374407756e693033374505746f6e6f730d6469657265736973746f6e6f730a41 +6c706861746f6e6f7309616e6f74656c6569610c457073696c6f6e746f6e6f7308457461746f6e6f7309496f7461746f6e6f +730c4f6d6963726f6e746f6e6f730c557073696c6f6e746f6e6f730a4f6d656761746f6e6f7311696f746164696572657369 +73746f6e6f7305416c70686104426574610547616d6d6107756e693033393407457073696c6f6e045a657461034574610554 +6865746104496f7461054b61707061064c616d626461024d75024e75025869074f6d6963726f6e0250690352686f05536967 +6d610354617507557073696c6f6e0350686903436869035073690c496f746164696572657369730f557073696c6f6e646965 +72657369730a616c706861746f6e6f730c657073696c6f6e746f6e6f7308657461746f6e6f7309696f7461746f6e6f731475 +7073696c6f6e6469657265736973746f6e6f7305616c70686104626574610567616d6d610564656c746107657073696c6f6e +047a6574610365746105746865746104696f7461056b61707061066c616d62646107756e6930334243026e75027869076f6d +6963726f6e0372686f067369676d6131057369676d610374617507757073696c6f6e037068690363686903707369056f6d65 +67610c696f746164696572657369730f757073696c6f6e64696572657369730c6f6d6963726f6e746f6e6f730c757073696c +6f6e746f6e6f730a6f6d656761746f6e6f7307756e693033434607756e69303344300674686574613108557073696c6f6e31 +07756e693033443307756e69303344340470686931066f6d6567613107756e693033443707756e693033443807756e693033 +443907756e693033444107756e693033444207756e693033444307756e693033444407756e693033444507756e6930334446 +07756e693033453007756e693033453107756e693033453207756e693033453307756e693033453407756e69303345350775 +6e693033453607756e693033453707756e693033453807756e693033453907756e693033454107756e693033454207756e69 +3033454307756e693033454407756e693033454507756e693033454607756e693033463007756e693033463107756e693033 +463207756e693033463307756e693033463407756e693033463507756e693033463607756e693033463707756e6930334638 +07756e693033463907756e693033464107756e693033464207756e693033464307756e693033464407756e69303346450775 +6e693033464607756e693034303007756e693034303107756e693034303207756e693034303307756e693034303407756e69 +3034303507756e693034303607756e693034303707756e693034303807756e693034303907756e693034304107756e693034 +304207756e693034304307756e693034304407756e693034304507756e693034304607756e693034313007756e6930343131 +07756e693034313207756e693034313307756e693034313407756e693034313507756e693034313607756e69303431370775 +6e693034313807756e693034313907756e693034314107756e693034314207756e693034314307756e693034314407756e69 +3034314507756e693034314607756e693034323007756e693034323107756e693034323207756e693034323307756e693034 +323407756e693034323507756e693034323607756e693034323707756e693034323807756e693034323907756e6930343241 +07756e693034324207756e693034324307756e693034324407756e693034324507756e693034324607756e69303433300775 +6e693034333107756e693034333207756e693034333307756e693034333407756e693034333507756e693034333607756e69 +3034333707756e693034333807756e693034333907756e693034334107756e693034334207756e693034334307756e693034 +334407756e693034334507756e693034334607756e693034343007756e693034343107756e693034343207756e6930343433 +07756e693034343407756e693034343507756e693034343607756e693034343707756e693034343807756e69303434390775 +6e693034344107756e693034344207756e693034344307756e693034344407756e693034344507756e693034344607756e69 +3034353007756e693034353107756e693034353207756e693034353307756e693034353407756e693034353507756e693034 +353607756e693034353707756e693034353807756e693034353907756e693034354107756e693034354207756e6930343543 +07756e693034354407756e693034354507756e693034354607756e693034363007756e693034363107756e69303436320775 +6e693034363307756e693034363407756e693034363507756e693034363607756e693034363707756e693034363807756e69 +3034363907756e693034364107756e693034364207756e693034364307756e693034364407756e693034364507756e693034 +364607756e693034373007756e693034373107756e693034373207756e693034373307756e693034373407756e6930343735 +07756e693034373607756e693034373707756e693034373807756e693034373907756e693034374107756e69303437420775 +6e693034374307756e693034374407756e693034374507756e693034374607756e693034383007756e693034383107756e69 +3034383207756e693034383307756e693034383407756e693034383507756e693034383607756e693034383707756e693034 +383807756e693034383907756e693034384107756e693034384207756e693034384307756e693034384407756e6930343845 +07756e693034384607756e693034393007756e693034393107756e693034393207756e693034393307756e69303439340775 +6e693034393507756e693034393607756e693034393707756e693034393807756e693034393907756e693034394107756e69 +3034394207756e693034394307756e693034394407756e693034394507756e693034394607756e693034413007756e693034 +413107756e693034413207756e693034413307756e693034413407756e693034413507756e693034413607756e6930344137 +07756e693034413807756e693034413907756e693034414107756e693034414207756e693034414307756e69303441440775 +6e693034414507756e693034414607756e693034423007756e693034423107756e693034423207756e693034423307756e69 +3034423407756e693034423507756e693034423607756e693034423707756e693034423807756e693034423907756e693034 +424107756e693034424207756e693034424307756e693034424407756e693034424507756e693034424607756e6930344330 +07756e693034433107756e693034433207756e693034433307756e693034433407756e693034433507756e69303443360775 +6e693034433707756e693034433807756e693034433907756e693034434107756e693034434207756e693034434307756e69 +3034434407756e693034434507756e693034434607756e693034443007756e693034443107756e693034443207756e693034 +443307756e693034443407756e693034443507756e693034443607756e693034443707756e693034443807756e6930344439 +07756e693034444107756e693034444207756e693034444307756e693034444407756e693034444507756e69303444460775 +6e693034453007756e693034453107756e693034453207756e693034453307756e693034453407756e693034453507756e69 +3034453607756e693034453707756e693034453807756e693034453907756e693034454107756e693034454207756e693034 +454307756e693034454407756e693034454507756e693034454607756e693034463007756e693034463107756e6930344632 +07756e693034463307756e693034463407756e693034463507756e693034463607756e693034463707756e69303446380775 +6e693034463907756e693034464107756e693034464207756e693034464307756e693034464407756e693034464507756e69 +3034464607756e693035303007756e693035303107756e693035303207756e693035303307756e693035303407756e693035 +303507756e693035303607756e693035303707756e693035303807756e693035303907756e693035304107756e6930353042 +07756e693035304307756e693035304407756e693035304507756e693035304607756e693035313007756e69303531310775 +6e693035313207756e693035313307756e693035313407756e693035313507756e693035313607756e693035313707756e69 +3035313807756e693035313907756e693035314107756e693035314207756e693035314307756e693035314407756e693035 +314507756e693035314607756e693035323007756e693035323107756e693035323207756e693035323307756e6930353234 +07756e693035323507756e693035333107756e693035333207756e693035333307756e693035333407756e69303533350775 +6e693035333607756e693035333707756e693035333807756e693035333907756e693035334107756e693035334207756e69 +3035334307756e693035334407756e693035334507756e693035334607756e693035343007756e693035343107756e693035 +343207756e693035343307756e693035343407756e693035343507756e693035343607756e693035343707756e6930353438 +07756e693035343907756e693035344107756e693035344207756e693035344307756e693035344407756e69303534450775 +6e693035344607756e693035353007756e693035353107756e693035353207756e693035353307756e693035353407756e69 +3035353507756e693035353607756e693035353907756e693035354107756e693035354207756e693035354307756e693035 +354407756e693035354507756e693035354607756e693035363107756e693035363207756e693035363307756e6930353634 +07756e693035363507756e693035363607756e693035363707756e693035363807756e693035363907756e69303536410775 +6e693035364207756e693035364307756e693035364407756e693035364507756e693035364607756e693035373007756e69 +3035373107756e693035373207756e693035373307756e693035373407756e693035373507756e693035373607756e693035 +373707756e693035373807756e693035373907756e693035374107756e693035374207756e693035374307756e6930353744 +07756e693035374507756e693035374607756e693035383007756e693035383107756e693035383207756e69303538330775 +6e693035383407756e693035383507756e693035383607756e693035383707756e693035383907756e693035384107756e69 +3035423007756e693035423107756e693035423207756e693035423307756e693035423407756e693035423507756e693035 +423607756e693035423707756e693035423807756e693035423907756e693035424107756e693035424207756e6930354243 +07756e693035424407756e693035424507756e693035424607756e693035433007756e693035433107756e69303543320775 +6e693035433307756e693035433607756e693035433707756e693035443007756e693035443107756e693035443207756e69 +3035443307756e693035443407756e693035443507756e693035443607756e693035443707756e693035443807756e693035 +443907756e693035444107756e693035444207756e693035444307756e693035444407756e693035444507756e6930354446 +07756e693035453007756e693035453107756e693035453207756e693035453307756e693035453407756e69303545350775 +6e693035453607756e693035453707756e693035453807756e693035453907756e693035454107756e693035463007756e69 +3035463107756e693035463207756e693035463307756e693035463407756e693036303607756e693036303707756e693036 +303907756e693036304107756e693036304307756e693036313507756e693036314207756e693036314607756e6930363231 +07756e693036323207756e693036323307756e693036323407756e693036323507756e693036323607756e69303632370775 +6e693036323807756e693036323907756e693036324107756e693036324207756e693036324307756e693036324407756e69 +3036324507756e693036324607756e693036333007756e693036333107756e693036333207756e693036333307756e693036 +333407756e693036333507756e693036333607756e693036333707756e693036333807756e693036333907756e6930363341 +07756e693036343007756e693036343107756e693036343207756e693036343307756e693036343407756e69303634350775 +6e693036343607756e693036343707756e693036343807756e693036343907756e693036344107756e693036344207756e69 +3036344307756e693036344407756e693036344507756e693036344607756e693036353007756e693036353107756e693036 +353207756e693036353307756e693036353407756e693036353507756e693036353707756e693036354107756e6930363630 +07756e693036363107756e693036363207756e693036363307756e693036363407756e693036363507756e69303636360775 +6e693036363707756e693036363807756e693036363907756e693036364107756e693036364207756e693036364307756e69 +3036364407756e693036364507756e693036364607756e693036373007756e693036373407756e693036373907756e693036 +374107756e693036374207756e693036374307756e693036374407756e693036374507756e693036374607756e6930363830 +07756e693036383107756e693036383207756e693036383307756e693036383407756e693036383507756e69303638360775 +6e693036383707756e693036383807756e693036383907756e693036384107756e693036384207756e693036384307756e69 +3036384407756e693036384507756e693036384607756e693036393007756e693036393107756e693036393207756e693036 +393307756e693036393407756e693036393507756e693036393607756e693036393707756e693036393807756e6930363939 +07756e693036394107756e693036394207756e693036394307756e693036394407756e693036394507756e69303639460775 +6e693036413007756e693036413107756e693036413207756e693036413307756e693036413407756e693036413507756e69 +3036413607756e693036413707756e693036413807756e693036413907756e693036414107756e693036414207756e693036 +414307756e693036414407756e693036414507756e693036414607756e693036423007756e693036423107756e6930364232 +07756e693036423307756e693036423407756e693036423507756e693036423607756e693036423707756e69303642380775 +6e693036423907756e693036424107756e693036424207756e693036424307756e693036424407756e693036424507756e69 +3036424607756e693036433607756e693036433707756e693036433807756e693036434207756e693036434307756e693036 +434507756e693036443007756e693036443507756e693036463007756e693036463107756e693036463207756e6930364633 +07756e693036463407756e693036463507756e693036463607756e693036463707756e693036463807756e69303646390775 +6e693037433007756e693037433107756e693037433207756e693037433307756e693037433407756e693037433507756e69 +3037433607756e693037433707756e693037433807756e693037433907756e693037434107756e693037434207756e693037 +434307756e693037434407756e693037434507756e693037434607756e693037443007756e693037443107756e6930374432 +07756e693037443307756e693037443407756e693037443507756e693037443607756e693037443707756e69303744380775 +6e693037443907756e693037444107756e693037444207756e693037444307756e693037444407756e693037444507756e69 +3037444607756e693037453007756e693037453107756e693037453207756e693037453307756e693037453407756e693037 +453507756e693037453607756e693037453707756e693037454207756e693037454307756e693037454407756e6930374545 +07756e693037454607756e693037463007756e693037463107756e693037463207756e693037463307756e69303746340775 +6e693037463507756e693037463807756e693037463907756e693037464107756e693045334607756e693045383107756e69 +3045383207756e693045383407756e693045383707756e693045383807756e693045384107756e693045384407756e693045 +393407756e693045393507756e693045393607756e693045393707756e693045393907756e693045394107756e6930453942 +07756e693045394307756e693045394407756e693045394507756e693045394607756e693045413107756e69304541320775 +6e693045413307756e693045413507756e693045413707756e693045414107756e693045414207756e693045414407756e69 +3045414507756e693045414607756e693045423007756e693045423107756e693045423207756e693045423307756e693045 +423407756e693045423507756e693045423607756e693045423707756e693045423807756e693045423907756e6930454242 +07756e693045424307756e693045424407756e693045433007756e693045433107756e693045433207756e69304543330775 +6e693045433407756e693045433607756e693045433807756e693045433907756e693045434107756e693045434207756e69 +3045434307756e693045434407756e693045443007756e693045443107756e693045443207756e693045443307756e693045 +443407756e693045443507756e693045443607756e693045443707756e693045443807756e693045443907756e6930454443 +07756e693045444407756e693130413007756e693130413107756e693130413207756e693130413307756e69313041340775 +6e693130413507756e693130413607756e693130413707756e693130413807756e693130413907756e693130414107756e69 +3130414207756e693130414307756e693130414407756e693130414507756e693130414607756e693130423007756e693130 +423107756e693130423207756e693130423307756e693130423407756e693130423507756e693130423607756e6931304237 +07756e693130423807756e693130423907756e693130424107756e693130424207756e693130424307756e69313042440775 +6e693130424507756e693130424607756e693130433007756e693130433107756e693130433207756e693130433307756e69 +3130433407756e693130433507756e693130443007756e693130443107756e693130443207756e693130443307756e693130 +443407756e693130443507756e693130443607756e693130443707756e693130443807756e693130443907756e6931304441 +07756e693130444207756e693130444307756e693130444407756e693130444507756e693130444607756e69313045300775 +6e693130453107756e693130453207756e693130453307756e693130453407756e693130453507756e693130453607756e69 +3130453707756e693130453807756e693130453907756e693130454107756e693130454207756e693130454307756e693130 +454407756e693130454507756e693130454607756e693130463007756e693130463107756e693130463207756e6931304633 +07756e693130463407756e693130463507756e693130463607756e693130463707756e693130463807756e69313046390775 +6e693130464107756e693130464207756e693130464307756e693134303107756e693134303207756e693134303307756e69 +3134303407756e693134303507756e693134303607756e693134303707756e693134303907756e693134304107756e693134 +304207756e693134304307756e693134304407756e693134304507756e693134304607756e693134313007756e6931343131 +07756e693134313207756e693134313307756e693134313407756e693134313507756e693134313607756e69313431370775 +6e693134313807756e693134313907756e693134314107756e693134314207756e693134314407756e693134314507756e69 +3134314607756e693134323007756e693134323107756e693134323207756e693134323307756e693134323407756e693134 +323507756e693134323607756e693134323707756e693134323807756e693134323907756e693134324107756e6931343242 +07756e693134324307756e693134324407756e693134324507756e693134324607756e693134333007756e69313433310775 +6e693134333207756e693134333307756e693134333407756e693134333507756e693134333707756e693134333807756e69 +3134333907756e693134334107756e693134334207756e693134334307756e693134334407756e693134334507756e693134 +334607756e693134343007756e693134343107756e693134343207756e693134343307756e693134343407756e6931343435 +07756e693134343607756e693134343707756e693134343807756e693134343907756e693134344107756e69313434430775 +6e693134344407756e693134344507756e693134344607756e693134353007756e693134353107756e693134353207756e69 +3134353407756e693134353507756e693134353607756e693134353707756e693134353807756e693134353907756e693134 +354107756e693134354207756e693134354307756e693134354407756e693134354507756e693134354607756e6931343630 +07756e693134363107756e693134363207756e693134363307756e693134363407756e693134363507756e69313436360775 +6e693134363707756e693134363807756e693134363907756e693134364107756e693134364207756e693134364307756e69 +3134364407756e693134364507756e693134364607756e693134373007756e693134373107756e693134373207756e693134 +373307756e693134373407756e693134373507756e693134373607756e693134373707756e693134373807756e6931343739 +07756e693134374107756e693134374207756e693134374307756e693134374407756e693134374507756e69313437460775 +6e693134383007756e693134383107756e693134383207756e693134383307756e693134383407756e693134383507756e69 +3134383607756e693134383707756e693134383807756e693134383907756e693134384107756e693134384207756e693134 +384307756e693134384407756e693134384507756e693134384607756e693134393007756e693134393107756e6931343932 +07756e693134393307756e693134393407756e693134393507756e693134393607756e693134393707756e69313439380775 +6e693134393907756e693134394107756e693134394207756e693134394307756e693134394407756e693134394507756e69 +3134394607756e693134413007756e693134413107756e693134413207756e693134413307756e693134413407756e693134 +413507756e693134413607756e693134413707756e693134413807756e693134413907756e693134414107756e6931344142 +07756e693134414307756e693134414407756e693134414507756e693134414607756e693134423007756e69313442310775 +6e693134423207756e693134423307756e693134423407756e693134423507756e693134423607756e693134423707756e69 +3134423807756e693134423907756e693134424107756e693134424207756e693134424307756e693134424407756e693134 +433007756e693134433107756e693134433207756e693134433307756e693134433407756e693134433507756e6931344336 +07756e693134433707756e693134433807756e693134433907756e693134434107756e693134434207756e69313443430775 +6e693134434407756e693134434507756e693134434607756e693134443007756e693134443107756e693134443207756e69 +3134443307756e693134443407756e693134443507756e693134443607756e693134443707756e693134443807756e693134 +443907756e693134444107756e693134444207756e693134444307756e693134444407756e693134444507756e6931344446 +07756e693134453007756e693134453107756e693134453207756e693134453307756e693134453407756e69313445350775 +6e693134453607756e693134453707756e693134453807756e693134453907756e693134454107756e693134454307756e69 +3134454407756e693134454507756e693134454607756e693134463007756e693134463107756e693134463207756e693134 +463307756e693134463407756e693134463507756e693134463607756e693134463707756e693134463807756e6931344639 +07756e693134464107756e693134464207756e693134464307756e693134464407756e693134464507756e69313446460775 +6e693135303007756e693135303107756e693135303207756e693135303307756e693135303407756e693135303507756e69 +3135303607756e693135303707756e693135313007756e693135313107756e693135313207756e693135313307756e693135 +313407756e693135313507756e693135313607756e693135313707756e693135313807756e693135313907756e6931353141 +07756e693135314207756e693135314307756e693135314407756e693135314507756e693135314607756e69313532300775 +6e693135323107756e693135323207756e693135323307756e693135323407756e693135323507756e693135323607756e69 +3135323707756e693135323807756e693135323907756e693135324107756e693135324207756e693135324307756e693135 +324407756e693135324507756e693135324607756e693135333007756e693135333107756e693135333207756e6931353333 +07756e693135333407756e693135333507756e693135333607756e693135333707756e693135333807756e69313533390775 +6e693135334107756e693135334207756e693135334307756e693135334407756e693135334507756e693135343007756e69 +3135343107756e693135343207756e693135343307756e693135343407756e693135343507756e693135343607756e693135 +343707756e693135343807756e693135343907756e693135344107756e693135344207756e693135344307756e6931353444 +07756e693135344507756e693135344607756e693135353007756e693135353207756e693135353307756e69313535340775 +6e693135353507756e693135353607756e693135353707756e693135353807756e693135353907756e693135354107756e69 +3135354207756e693135354307756e693135354407756e693135354507756e693135354607756e693135363007756e693135 +363107756e693135363207756e693135363307756e693135363407756e693135363507756e693135363607756e6931353637 +07756e693135363807756e693135363907756e693135364107756e693135373407756e693135373507756e69313537360775 +6e693135373707756e693135373807756e693135373907756e693135374107756e693135374207756e693135374307756e69 +3135374407756e693135374507756e693135374607756e693135383007756e693135383107756e693135383207756e693135 +383307756e693135383407756e693135383507756e693135384107756e693135384207756e693135384307756e6931353844 +07756e693135384507756e693135384607756e693135393007756e693135393107756e693135393207756e69313539330775 +6e693135393407756e693135393507756e693135393607756e693135413007756e693135413107756e693135413207756e69 +3135413307756e693135413407756e693135413507756e693135413607756e693135413707756e693135413807756e693135 +413907756e693135414107756e693135414207756e693135414307756e693135414407756e693135414507756e6931354146 +07756e693135444507756e693135453107756e693136343607756e693136343707756e693136364507756e69313636460775 +6e693136373007756e693136373107756e693136373207756e693136373307756e693136373407756e693136373507756e69 +3136373607756e693136383007756e693136383107756e693136383207756e693136383307756e693136383407756e693136 +383507756e693136383607756e693136383707756e693136383807756e693136383907756e693136384107756e6931363842 +07756e693136384307756e693136384407756e693136384507756e693136384607756e693136393007756e69313639310775 +6e693136393207756e693136393307756e693136393407756e693136393507756e693136393607756e693136393707756e69 +3136393807756e693136393907756e693136394107756e693136394207756e693136394307756e693144303007756e693144 +303107756e693144303207756e693144303307756e693144303407756e693144303507756e693144303607756e6931443037 +07756e693144303807756e693144303907756e693144304107756e693144304207756e693144304307756e69314430440775 +6e693144304507756e693144304607756e693144313007756e693144313107756e693144313207756e693144313307756e69 +3144313407756e693144313607756e693144313707756e693144313807756e693144313907756e693144314107756e693144 +314207756e693144314307756e693144314407756e693144314507756e693144314607756e693144323007756e6931443231 +07756e693144323207756e693144323307756e693144323607756e693144323707756e693144323807756e69314432390775 +6e693144324107756e693144324207756e693144324307756e693144324407756e693144324507756e693144333007756e69 +3144333107756e693144333207756e693144333307756e693144333407756e693144333507756e693144333607756e693144 +333707756e693144333807756e693144333907756e693144334107756e693144334207756e693144334307756e6931443344 +07756e693144334507756e693144334607756e693144343007756e693144343107756e693144343207756e69314434330775 +6e693144343407756e693144343507756e693144343607756e693144343707756e693144343807756e693144343907756e69 +3144344107756e693144344207756e693144344307756e693144344407756e693144344507756e693144344607756e693144 +353007756e693144353107756e693144353207756e693144353307756e693144353407756e693144353507756e6931443536 +07756e693144353707756e693144353807756e693144353907756e693144354107756e693144354207756e69314435440775 +6e693144354507756e693144354607756e693144363007756e693144363107756e693144363207756e693144363307756e69 +3144363407756e693144363507756e693144363607756e693144363707756e693144363807756e693144363907756e693144 +364107756e693144373707756e693144373807756e693144374207756e693144374407756e693144383507756e6931443942 +07756e693144394307756e693144394407756e693144394507756e693144394607756e693144413007756e69314441310775 +6e693144413207756e693144413307756e693144413407756e693144413507756e693144413607756e693144413707756e69 +3144413807756e693144413907756e693144414107756e693144414207756e693144414307756e693144414407756e693144 +414507756e693144414607756e693144423007756e693144423107756e693144423207756e693144423307756e6931444234 +07756e693144423507756e693144423607756e693144423707756e693144423807756e693144423907756e69314442410775 +6e693144424207756e693144424307756e693144424407756e693144424507756e693144424607756e693144433407756e69 +3144433507756e693144433607756e693144433707756e693144433807756e693144433907756e693145303007756e693145 +303107756e693145303207756e693145303307756e693145303407756e693145303507756e693145303607756e6931453037 +07756e693145303807756e693145303907756e693145304107756e693145304207756e693145304307756e69314530440775 +6e693145304507756e693145304607756e693145313007756e693145313107756e693145313207756e693145313307756e69 +3145313407756e693145313507756e693145313607756e693145313707756e693145313807756e693145313907756e693145 +314107756e693145314207756e693145314307756e693145314407756e693145314507756e693145314607756e6931453230 +07756e693145323107756e693145323207756e693145323307756e693145323407756e693145323507756e69314532360775 +6e693145323707756e693145323807756e693145323907756e693145324107756e693145324207756e693145324307756e69 +3145324407756e693145324507756e693145324607756e693145333007756e693145333107756e693145333207756e693145 +333307756e693145333407756e693145333507756e693145333607756e693145333707756e693145333807756e6931453339 +07756e693145334107756e693145334207756e693145334307756e693145334407756e693145334507756e69314533460775 +6e693145343007756e693145343107756e693145343207756e693145343307756e693145343407756e693145343507756e69 +3145343607756e693145343707756e693145343807756e693145343907756e693145344107756e693145344207756e693145 +344307756e693145344407756e693145344507756e693145344607756e693145353007756e693145353107756e6931453532 +07756e693145353307756e693145353407756e693145353507756e693145353607756e693145353707756e69314535380775 +6e693145353907756e693145354107756e693145354207756e693145354307756e693145354407756e693145354507756e69 +3145354607756e693145363007756e693145363107756e693145363207756e693145363307756e693145363407756e693145 +363507756e693145363607756e693145363707756e693145363807756e693145363907756e693145364107756e6931453642 +07756e693145364307756e693145364407756e693145364507756e693145364607756e693145373007756e69314537310775 +6e693145373207756e693145373307756e693145373407756e693145373507756e693145373607756e693145373707756e69 +3145373807756e693145373907756e693145374107756e693145374207756e693145374307756e693145374407756e693145 +374507756e693145374606576772617665067767726176650657616375746506776163757465095764696572657369730977 +646965726573697307756e693145383607756e693145383707756e693145383807756e693145383907756e69314538410775 +6e693145384207756e693145384307756e693145384407756e693145384507756e693145384607756e693145393007756e69 +3145393107756e693145393207756e693145393307756e693145393407756e693145393507756e693145393607756e693145 +393707756e693145393807756e693145393907756e693145394107756e693145394207756e693145394307756e6931453944 +07756e693145394507756e693145394607756e693145413007756e693145413107756e693145413207756e69314541330775 +6e693145413407756e693145413507756e693145413607756e693145413707756e693145413807756e693145413907756e69 +3145414107756e693145414207756e693145414307756e693145414407756e693145414507756e693145414607756e693145 +423007756e693145423107756e693145423207756e693145423307756e693145423407756e693145423507756e6931454236 +07756e693145423707756e693145423807756e693145423907756e693145424107756e693145424207756e69314542430775 +6e693145424407756e693145424507756e693145424607756e693145433007756e693145433107756e693145433207756e69 +3145433307756e693145433407756e693145433507756e693145433607756e693145433707756e693145433807756e693145 +433907756e693145434107756e693145434207756e693145434307756e693145434407756e693145434507756e6931454346 +07756e693145443007756e693145443107756e693145443207756e693145443307756e693145443407756e69314544350775 +6e693145443607756e693145443707756e693145443807756e693145443907756e693145444107756e693145444207756e69 +3145444307756e693145444407756e693145444507756e693145444607756e693145453007756e693145453107756e693145 +453207756e693145453307756e693145453407756e693145453507756e693145453607756e693145453707756e6931454538 +07756e693145453907756e693145454107756e693145454207756e693145454307756e693145454407756e69314545450775 +6e693145454607756e693145463007756e6931454631065967726176650679677261766507756e693145463407756e693145 +463507756e693145463607756e693145463707756e693145463807756e693145463907756e693145464107756e6931454642 +07756e693146303007756e693146303107756e693146303207756e693146303307756e693146303407756e69314630350775 +6e693146303607756e693146303707756e693146303807756e693146303907756e693146304107756e693146304207756e69 +3146304307756e693146304407756e693146304507756e693146304607756e693146313007756e693146313107756e693146 +313207756e693146313307756e693146313407756e693146313507756e693146313807756e693146313907756e6931463141 +07756e693146314207756e693146314307756e693146314407756e693146323007756e693146323107756e69314632320775 +6e693146323307756e693146323407756e693146323507756e693146323607756e693146323707756e693146323807756e69 +3146323907756e693146324107756e693146324207756e693146324307756e693146324407756e693146324507756e693146 +324607756e693146333007756e693146333107756e693146333207756e693146333307756e693146333407756e6931463335 +07756e693146333607756e693146333707756e693146333807756e693146333907756e693146334107756e69314633420775 +6e693146334307756e693146334407756e693146334507756e693146334607756e693146343007756e693146343107756e69 +3146343207756e693146343307756e693146343407756e693146343507756e693146343807756e693146343907756e693146 +344107756e693146344207756e693146344307756e693146344407756e693146353007756e693146353107756e6931463532 +07756e693146353307756e693146353407756e693146353507756e693146353607756e693146353707756e69314635390775 +6e693146354207756e693146354407756e693146354607756e693146363007756e693146363107756e693146363207756e69 +3146363307756e693146363407756e693146363507756e693146363607756e693146363707756e693146363807756e693146 +363907756e693146364107756e693146364207756e693146364307756e693146364407756e693146364507756e6931463646 +07756e693146373007756e693146373107756e693146373207756e693146373307756e693146373407756e69314637350775 +6e693146373607756e693146373707756e693146373807756e693146373907756e693146374107756e693146374207756e69 +3146374307756e693146374407756e693146383007756e693146383107756e693146383207756e693146383307756e693146 +383407756e693146383507756e693146383607756e693146383707756e693146383807756e693146383907756e6931463841 +07756e693146384207756e693146384307756e693146384407756e693146384507756e693146384607756e69314639300775 +6e693146393107756e693146393207756e693146393307756e693146393407756e693146393507756e693146393607756e69 +3146393707756e693146393807756e693146393907756e693146394107756e693146394207756e693146394307756e693146 +394407756e693146394507756e693146394607756e693146413007756e693146413107756e693146413207756e6931464133 +07756e693146413407756e693146413507756e693146413607756e693146413707756e693146413807756e69314641390775 +6e693146414107756e693146414207756e693146414307756e693146414407756e693146414507756e693146414607756e69 +3146423007756e693146423107756e693146423207756e693146423307756e693146423407756e693146423607756e693146 +423707756e693146423807756e693146423907756e693146424107756e693146424207756e693146424307756e6931464244 +07756e693146424507756e693146424607756e693146433007756e693146433107756e693146433207756e69314643330775 +6e693146433407756e693146433607756e693146433707756e693146433807756e693146433907756e693146434107756e69 +3146434207756e693146434307756e693146434407756e693146434507756e693146434607756e693146443007756e693146 +443107756e693146443207756e693146443307756e693146443607756e693146443707756e693146443807756e6931464439 +07756e693146444107756e693146444207756e693146444407756e693146444507756e693146444607756e69314645300775 +6e693146453107756e693146453207756e693146453307756e693146453407756e693146453507756e693146453607756e69 +3146453707756e693146453807756e693146453907756e693146454107756e693146454207756e693146454307756e693146 +454407756e693146454507756e693146454607756e693146463207756e693146463307756e693146463407756e6931464636 +07756e693146463707756e693146463807756e693146463907756e693146464107756e693146464207756e69314646430775 +6e693146464407756e693146464507756e693230303007756e693230303107756e693230303207756e693230303307756e69 +3230303407756e693230303507756e693230303607756e693230303707756e693230303807756e693230303907756e693230 +304107756e693230304207756e693230304307756e693230304407756e693230304507756e693230304607756e6932303130 +07756e69323031310a6669677572656461736807756e693230313507756e69323031360d756e64657273636f726564626c0d +71756f7465726576657273656407756e693230314607756e69323032330e6f6e65646f74656e6c65616465720e74776f646f +74656e6c656164657207756e693230323707756e693230323807756e693230323907756e693230324107756e693230324207 +756e693230324307756e693230324407756e693230324507756e693230324607756e6932303331066d696e75746506736563 +6f6e6407756e693230333407756e693230333507756e693230333607756e693230333707756e693230333807756e69323033 +42096578636c616d64626c07756e693230334407756e693230334507756e693230334607756e693230343007756e69323034 +3107756e693230343207756e693230343307756e693230343507756e693230343607756e693230343707756e693230343807 +756e693230343907756e693230344107756e693230344207756e693230344307756e693230344407756e693230344507756e +693230344607756e693230353007756e693230353107756e693230353207756e693230353307756e693230353407756e6932 +30353507756e693230353607756e693230353707756e693230353807756e693230353907756e693230354107756e69323035 +4207756e693230354307756e693230354407756e693230354507756e693230354607756e693230363007756e693230363107 +756e693230363207756e693230363307756e693230363407756e693230364107756e693230364207756e693230364307756e +693230364407756e693230364507756e693230364607756e693230373007756e693230373107756e693230373407756e6932 +30373507756e693230373607756e693230373707756e693230373807756e693230373907756e693230374107756e69323037 +4207756e693230374307756e693230374407756e693230374507756e693230374607756e693230383007756e693230383107 +756e693230383207756e693230383307756e693230383407756e693230383507756e693230383607756e693230383707756e +693230383807756e693230383907756e693230384107756e693230384207756e693230384307756e693230384407756e6932 +30384507756e693230393007756e693230393107756e693230393207756e693230393307756e693230393407756e69323039 +3507756e693230393607756e693230393707756e693230393807756e693230393907756e693230394107756e693230394207 +756e693230394307756e69323041300d636f6c6f6e6d6f6e657461727907756e6932304132046c69726107756e6932304135 +07756e69323041360670657365746107756e693230413807756e693230413907756e693230414104646f6e67044575726f07 +756e693230414407756e693230414507756e693230414607756e693230423007756e693230423107756e693230423207756e +693230423307756e693230423407756e693230423507756e693230423807756e693230423907756e693230424107756e6932 +30424407756e693230443007756e693230443107756e693230443607756e693230443707756e693230444207756e69323044 +4307756e693230453107756e693231303007756e693231303107756e693231303207756e693231303307756e693231303407 +756e693231303507756e693231303607756e693231303707756e693231303807756e693231303907756e693231304207756e +693231304307756e693231304407756e693231304507756e693231304607756e693231313008496672616b74757207756e69 +3231313207756e693231313307756e693231313407756e693231313507756e693231313607756e69323131370b7765696572 +73747261737307756e693231313907756e693231314107756e693231314208526672616b74757207756e69323131440c7072 +65736372697074696f6e07756e693231314607756e693231323007756e693231323107756e693231323307756e6932313234 +07756e693231323507756e693231323607756e693231323707756e693231323807756e693231323907756e69323132410775 +6e693231324207756e693231324307756e693231324409657374696d6174656407756e693231324607756e69323133300775 +6e693231333107756e693231333207756e693231333307756e693231333405616c65706807756e693231333607756e693231 +333707756e693231333807756e693231333907756e693231334107756e693231334207756e693231334307756e6932313344 +07756e693231334507756e693231334607756e693231343007756e693231343107756e693231343207756e69323134330775 +6e693231343407756e693231343507756e693231343607756e693231343707756e693231343807756e693231343907756e69 +3231344207756e693231344507756e693231353007756e693231353107756e6932313532086f6e6574686972640974776f74 +686972647307756e693231353507756e693231353607756e693231353707756e693231353807756e693231353907756e6932 +313541096f6e656569676874680c7468726565656967687468730b66697665656967687468730c736576656e656967687468 +7307756e693231354607756e693231363007756e693231363107756e693231363207756e693231363307756e693231363407 +756e693231363507756e693231363607756e693231363707756e693231363807756e693231363907756e693231364107756e +693231364207756e693231364307756e693231364407756e693231364507756e693231364607756e693231373007756e6932 +31373107756e693231373207756e693231373307756e693231373407756e693231373507756e693231373607756e69323137 +3707756e693231373807756e693231373907756e693231374107756e693231374207756e693231374307756e693231374407 +756e693231374507756e693231374607756e693231383007756e693231383107756e693231383207756e693231383307756e +693231383407756e693231383507756e6932313839096172726f776c656674076172726f7775700a6172726f777269676874 +096172726f77646f776e096172726f77626f7468096172726f777570646e07756e693231393607756e693231393707756e69 +3231393807756e693231393907756e693231394107756e693231394207756e693231394307756e693231394407756e693231 +394507756e693231394607756e693231413007756e693231413107756e693231413207756e693231413307756e6932314134 +07756e693231413507756e693231413607756e69323141370c6172726f777570646e62736507756e693231413907756e6932 +31414107756e693231414207756e693231414307756e693231414407756e693231414507756e693231414607756e69323142 +3007756e693231423107756e693231423207756e693231423307756e69323142340e636172726961676572657475726e0775 +6e693231423607756e693231423707756e693231423807756e693231423907756e693231424107756e693231424207756e69 +3231424307756e693231424407756e693231424507756e693231424607756e693231433007756e693231433107756e693231 +433207756e693231433307756e693231433407756e693231433507756e693231433607756e693231433707756e6932314338 +07756e693231433907756e693231434107756e693231434207756e693231434307756e693231434407756e69323143450775 +6e69323143460c6172726f7764626c6c6566740a6172726f7764626c75700d6172726f7764626c72696768740c6172726f77 +64626c646f776e0c6172726f7764626c626f746807756e693231443507756e693231443607756e693231443707756e693231 +443807756e693231443907756e693231444107756e693231444207756e693231444307756e693231444407756e6932314445 +07756e693231444607756e693231453007756e693231453107756e693231453207756e693231453307756e69323145340775 +6e693231453507756e693231453607756e693231453707756e693231453807756e693231453907756e693231454107756e69 +3231454207756e693231454307756e693231454407756e693231454507756e693231454607756e693231463007756e693231 +463107756e693231463207756e693231463307756e693231463407756e693231463507756e693231463607756e6932314637 +07756e693231463807756e693231463907756e693231464107756e693231464207756e693231464307756e69323146440775 +6e693231464507756e693231464609756e6976657273616c07756e69323230310b6578697374656e7469616c07756e693232 +303408656d707479736574086772616469656e7407656c656d656e740a6e6f74656c656d656e7407756e6932323041087375 +63687468617407756e693232304307756e693232304407756e693232304507756e693232313007756e693232313307756e69 +3232313407756e693232313507756e69323231360c617374657269736b6d61746807756e693232313807756e693232313907 +756e693232314207756e69323231430c70726f706f7274696f6e616c0a6f7274686f676f6e616c05616e676c6507756e6932 +32323107756e693232323207756e693232323307756e693232323407756e693232323507756e69323232360a6c6f67696361 +6c616e64096c6f676963616c6f720c696e74657273656374696f6e05756e696f6e07756e693232324307756e693232324407 +756e693232324507756e693232324607756e693232333007756e693232333107756e693232333207756e6932323333097468 +657265666f726507756e693232333507756e693232333607756e693232333707756e693232333807756e693232333907756e +693232334107756e69323233420773696d696c617207756e693232334407756e693232334507756e693232334607756e6932 +32343007756e693232343107756e693232343207756e693232343307756e693232343409636f6e677275656e7407756e6932 +32343607756e693232343707756e693232343907756e693232344107756e693232344207756e693232344307756e69323234 +4407756e693232344507756e693232344607756e693232353007756e693232353107756e693232353207756e693232353307 +756e693232353407756e693232353507756e693232353607756e693232353707756e693232353807756e693232353907756e +693232354107756e693232354207756e693232354307756e693232354407756e693232354507756e69323235460b65717569 +76616c656e636507756e693232363207756e693232363307756e693232363607756e693232363707756e693232363807756e +693232363907756e693232364107756e693232364207756e693232364307756e693232364407756e693232364507756e6932 +32364607756e693232373007756e693232373107756e693232373207756e693232373307756e693232373407756e69323237 +3507756e693232373607756e693232373707756e693232373807756e693232373907756e693232374107756e693232374207 +756e693232374307756e693232374407756e693232374507756e693232374607756e693232383007756e69323238310c7072 +6f7065727375627365740e70726f7065727375706572736574096e6f7473756273657407756e69323238350c7265666c6578 +7375627365740e7265666c6578737570657273657407756e693232383807756e693232383907756e693232384107756e6932 +32384207756e693232384307756e693232384407756e693232384507756e693232384607756e693232393007756e69323239 +3107756e693232393207756e693232393307756e69323239340a636972636c65706c757307756e69323239360e636972636c +656d756c7469706c7907756e693232393807756e693232393907756e693232394107756e693232394207756e693232394307 +756e693232394407756e693232394507756e693232394607756e693232413007756e693232413107756e693232413207756e +693232413307756e69323241340d70657270656e646963756c617207756e693232413607756e693232413707756e69323241 +3807756e693232413907756e693232414107756e693232414207756e693232414307756e693232414407756e693232414507 +756e693232414607756e693232423007756e693232423107756e693232423207756e693232423307756e693232423407756e +693232423507756e693232423607756e693232423707756e693232423807756e693232423907756e693232424107756e6932 +32424207756e693232424307756e693232424407756e693232424507756e693232424607756e693232433007756e69323243 +3107756e693232433207756e693232433307756e693232433407646f746d61746807756e693232433607756e693232433707 +756e693232433807756e693232433907756e693232434107756e693232434207756e693232434307756e693232434407756e +693232434507756e693232434607756e693232443007756e693232443107756e693232443207756e693232443307756e6932 +32443407756e693232443507756e693232443607756e693232443707756e693232443807756e693232443907756e69323244 +4107756e693232444207756e693232444307756e693232444407756e693232444507756e693232444607756e693232453007 +756e693232453107756e693232453207756e693232453307756e693232453407756e693232453507756e693232453607756e +693232453707756e693232453807756e693232453907756e693232454107756e693232454207756e693232454307756e6932 +32454407756e693232454507756e693232454607756e693232463007756e693232463107756e693232463207756e69323246 +3307756e693232463407756e693232463507756e693232463607756e693232463707756e693232463807756e693232463907 +756e693232464107756e693232464207756e693232464307756e693232464407756e693232464507756e693232464607756e +693233303007756e693233303105686f75736507756e693233303307756e693233303407756e693233303507756e69323330 +3607756e693233303707756e693233303807756e693233303907756e693233304107756e693233304207756e693233304307 +756e693233304407756e693233304507756e69323330460d7265766c6f676963616c6e6f7407756e693233313107756e6932 +33313807756e693233313907756e693233314307756e693233314407756e693233314507756e69323331460a696e74656772 +616c74700a696e74656772616c627407756e693233323407756e693233323507756e693233323607756e693233323707756e +693233323807756e693233324207756e693233324307756e693233373307756e693233373407756e693233373507756e6932 +33374107756e693233374407756e693233383707756e693233393407756e693233394207756e693233394307756e69323339 +4407756e693233394507756e693233394607756e693233413007756e693233413107756e693233413207756e693233413307 +756e693233413407756e693233413507756e693233413607756e693233413707756e693233413807756e693233413907756e +693233414107756e693233414207756e693233414307756e693233414407756e693233414507756e693233434507756e6932 +33434607756e693233453307756e693233453507756e693233453807756e693234323207756e693234323307756e69323436 +3007756e693234363107756e693234363207756e693234363307756e693234363407756e693234363507756e693234363607 +756e693234363707756e693234363807756e693234363908534631303030303007756e693235303108534631313030303007 +756e693235303307756e693235303407756e693235303507756e693235303607756e693235303707756e693235303807756e +693235303907756e693235304107756e693235304208534630313030303007756e693235304407756e693235304507756e69 +3235304608534630333030303007756e693235313107756e693235313207756e693235313308534630323030303007756e69 +3235313507756e693235313607756e693235313708534630343030303007756e693235313907756e693235314107756e6932 +35314208534630383030303007756e693235314407756e693235314507756e693235314607756e693235323007756e693235 +323107756e693235323207756e693235323308534630393030303007756e693235323507756e693235323607756e69323532 +3707756e693235323807756e693235323907756e693235324107756e693235324208534630363030303007756e6932353244 +07756e693235324507756e693235324607756e693235333007756e693235333107756e693235333207756e69323533330853 +4630373030303007756e693235333507756e693235333607756e693235333707756e693235333807756e693235333907756e +693235334107756e693235334208534630353030303007756e693235334407756e693235334507756e693235334607756e69 +3235343007756e693235343107756e693235343207756e693235343307756e693235343407756e693235343507756e693235 +343607756e693235343707756e693235343807756e693235343907756e693235344107756e693235344207756e6932353443 +07756e693235344407756e693235344507756e69323534460853463433303030300853463234303030300853463531303030 +3008534635323030303008534633393030303008534632323030303008534632313030303008534632353030303008534635 +3030303030085346343930303030085346333830303030085346323830303030085346323730303030085346323630303030 +0853463336303030300853463337303030300853463432303030300853463139303030300853463230303030300853463233 +3030303008534634373030303008534634383030303008534634313030303008534634353030303008534634363030303008 +534634303030303008534635343030303008534635333030303008534634343030303007756e693235364407756e69323536 +4507756e693235364607756e693235373007756e693235373107756e693235373207756e693235373307756e693235373407 +756e693235373507756e693235373607756e693235373707756e693235373807756e693235373907756e693235374107756e +693235374207756e693235374307756e693235374407756e693235374507756e6932353746077570626c6f636b07756e6932 +35383107756e693235383207756e693235383307646e626c6f636b07756e693235383507756e693235383607756e69323538 +3705626c6f636b07756e693235383907756e693235384107756e6932353842076c66626c6f636b07756e693235384407756e +693235384507756e6932353846077274626c6f636b076c74736861646505736861646507646b736861646507756e69323539 +3407756e693235393507756e693235393607756e693235393707756e693235393807756e693235393907756e693235394107 +756e693235394207756e693235394307756e693235394407756e693235394507756e69323539460966696c6c6564626f7806 +48323230373307756e693235413207756e693235413307756e693235413407756e693235413507756e693235413607756e69 +3235413707756e693235413807756e693235413906483138353433064831383535310a66696c6c65647265637407756e6932 +35414407756e693235414507756e693235414607756e693235423007756e6932354231077472696167757007756e69323542 +3307756e693235423407756e693235423507756e693235423607756e693235423707756e693235423807756e693235423907 +7472696167727407756e6932354242077472696167646e07756e693235424407756e693235424507756e693235424607756e +693235433007756e693235433107756e693235433207756e69323543330774726961676c6607756e693235433507756e6932 +35433607756e693235433707756e693235433807756e693235433906636972636c6507756e693235434307756e6932354344 +07756e69323543450648313835333307756e693235443007756e693235443107756e693235443207756e693235443307756e +693235443407756e693235443507756e693235443607756e693235443709696e7662756c6c657409696e76636972636c6507 +756e693235444107756e693235444207756e693235444307756e693235444407756e693235444507756e693235444607756e +693235453007756e693235453107756e693235453207756e693235453307756e693235453407756e69323545350a6f70656e +62756c6c657407756e693235453707756e693235453807756e693235453907756e693235454107756e693235454207756e69 +3235454307756e693235454407756e693235454507756e693235454607756e693235463007756e693235463107756e693235 +463207756e693235463307756e693235463407756e693235463507756e693235463607756e693235463707756e6932354638 +07756e693235463907756e693235464107756e693235464207756e693235464307756e693235464407756e69323546450775 +6e693235464607756e693236303007756e693236303107756e693236303207756e693236303307756e693236303407756e69 +3236303507756e693236303607756e693236303707756e693236303807756e693236303907756e693236304107756e693236 +304207756e693236304307756e693236304407756e693236304507756e693236304607756e693236313007756e6932363131 +07756e693236313207756e693236313307756e693236313407756e693236313507756e693236313607756e69323631370775 +6e693236313807756e693236313907756e693236314107756e693236314207756e693236314307756e693236314407756e69 +3236314507756e693236314607756e693236323007756e693236323107756e693236323207756e693236323307756e693236 +323407756e693236323507756e693236323607756e693236323707756e693236323807756e693236323907756e6932363241 +07756e693236324207756e693236324307756e693236324407756e693236324507756e693236324607756e69323633300775 +6e693236333107756e693236333207756e693236333307756e693236333407756e693236333507756e693236333607756e69 +3236333707756e693236333807756e693236333909736d696c65666163650c696e76736d696c65666163650373756e07756e +693236334407756e693236334507756e69323633460666656d616c6507756e6932363431046d616c6507756e693236343307 +756e693236343407756e693236343507756e693236343607756e693236343707756e693236343807756e693236343907756e +693236344107756e693236344207756e693236344307756e693236344407756e693236344507756e693236344607756e6932 +36353007756e693236353107756e693236353207756e693236353307756e693236353407756e693236353507756e69323635 +3607756e693236353707756e693236353807756e693236353907756e693236354107756e693236354207756e693236354307 +756e693236354407756e693236354507756e693236354605737061646507756e693236363107756e693236363204636c7562 +07756e6932363634056865617274076469616d6f6e6407756e693236363707756e693236363807756e69323636390b6d7573 +6963616c6e6f74650e6d75736963616c6e6f746564626c07756e693236364307756e693236364407756e693236364507756e +693236364607756e693236373007756e693236373107756e693236373207756e693236373307756e693236373407756e6932 +36373507756e693236373607756e693236373707756e693236373807756e693236373907756e693236374107756e69323637 +4207756e693236374307756e693236374407756e693236374507756e693236374607756e693236383007756e693236383107 +756e693236383207756e693236383307756e693236383407756e693236383507756e693236383607756e693236383707756e +693236383807756e693236383907756e693236384107756e693236384207756e693236384307756e693236384407756e6932 +36384507756e693236384607756e693236393007756e693236393107756e693236393207756e693236393307756e69323639 +3407756e693236393507756e693236393607756e693236393707756e693236393807756e693236393907756e693236394107 +756e693236394207756e693236394307756e693236394507756e693236394607756e693236413007756e693236413107756e +693236413207756e693236413307756e693236413407756e693236413507756e693236413607756e693236413707756e6932 +36413807756e693236413907756e693236414107756e693236414207756e693236414307756e693236414407756e69323641 +4507756e693236414607756e693236423007756e693236423107756e693236423207756e693236423307756e693236423407 +756e693236423507756e693236423607756e693236423707756e693236423807756e693236433007756e693236433107756e +693236433207756e693236433307756e693236453207756e693237303107756e693237303207756e693237303307756e6932 +37303407756e693237303607756e693237303707756e693237303807756e693237303907756e693237304307756e69323730 +4407756e693237304507756e693237304607756e693237313007756e693237313107756e693237313207756e693237313307 +756e693237313407756e693237313507756e693237313607756e693237313707756e693237313807756e693237313907756e +693237314107756e693237314207756e693237314307756e693237314407756e693237314507756e693237314607756e6932 +37323007756e693237323107756e693237323207756e693237323307756e693237323407756e693237323507756e69323732 +3607756e693237323707756e693237323907756e693237324107756e693237324207756e693237324307756e693237324407 +756e693237324507756e693237324607756e693237333007756e693237333107756e693237333207756e693237333307756e +693237333407756e693237333507756e693237333607756e693237333707756e693237333807756e693237333907756e6932 +37334107756e693237334207756e693237334307756e693237334407756e693237334507756e693237334607756e69323734 +3007756e693237343107756e693237343207756e693237343307756e693237343407756e693237343507756e693237343607 +756e693237343707756e693237343807756e693237343907756e693237344107756e693237344207756e693237344407756e +693237344607756e693237353007756e693237353107756e693237353207756e693237353607756e693237353807756e6932 +37353907756e693237354107756e693237354207756e693237354307756e693237354407756e693237354507756e69323736 +3107756e693237363207756e693237363307756e693237363407756e693237363507756e693237363607756e693237363707 +756e693237363807756e693237363907756e693237364107756e693237364207756e693237364307756e693237364407756e +693237364507756e693237364607756e693237373007756e693237373107756e693237373207756e693237373307756e6932 +37373407756e693237373507756e693237373607756e693237373707756e693237373807756e693237373907756e69323737 +4107756e693237374207756e693237374307756e693237374407756e693237374507756e693237374607756e693237383007 +756e693237383107756e693237383207756e693237383307756e693237383407756e693237383507756e693237383607756e +693237383707756e693237383807756e693237383907756e693237384107756e693237384207756e693237384307756e6932 +37384407756e693237384507756e693237384607756e693237393007756e693237393107756e693237393207756e69323739 +3307756e693237393407756e693237393807756e693237393907756e693237394107756e693237394207756e693237394307 +756e693237394407756e693237394507756e693237394607756e693237413007756e693237413107756e693237413207756e +693237413307756e693237413407756e693237413507756e693237413607756e693237413707756e693237413807756e6932 +37413907756e693237414107756e693237414207756e693237414307756e693237414407756e693237414507756e69323741 +4607756e693237423107756e693237423207756e693237423307756e693237423407756e693237423507756e693237423607 +756e693237423707756e693237423807756e693237423907756e693237424107756e693237424207756e693237424307756e +693237424407756e693237424507756e693237433507756e693237433607756e693237453007756e693237453607756e6932 +37453707756e693237453807756e693237453907756e693237454107756e693237454207756e693237463007756e69323746 +3107756e693237463207756e693237463307756e693237463407756e693237463507756e693237463607756e693237463707 +756e693237463807756e693237463907756e693237464107756e693237464207756e693237464307756e693237464407756e +693237464507756e693237464607756e693238303007756e693238303107756e693238303207756e693238303307756e6932 +38303407756e693238303507756e693238303607756e693238303707756e693238303807756e693238303907756e69323830 +4107756e693238304207756e693238304307756e693238304407756e693238304507756e693238304607756e693238313007 +756e693238313107756e693238313207756e693238313307756e693238313407756e693238313507756e693238313607756e +693238313707756e693238313807756e693238313907756e693238314107756e693238314207756e693238314307756e6932 +38314407756e693238314507756e693238314607756e693238323007756e693238323107756e693238323207756e69323832 +3307756e693238323407756e693238323507756e693238323607756e693238323707756e693238323807756e693238323907 +756e693238324107756e693238324207756e693238324307756e693238324407756e693238324507756e693238324607756e +693238333007756e693238333107756e693238333207756e693238333307756e693238333407756e693238333507756e6932 +38333607756e693238333707756e693238333807756e693238333907756e693238334107756e693238334207756e69323833 +4307756e693238334407756e693238334507756e693238334607756e693238343007756e693238343107756e693238343207 +756e693238343307756e693238343407756e693238343507756e693238343607756e693238343707756e693238343807756e +693238343907756e693238344107756e693238344207756e693238344307756e693238344407756e693238344507756e6932 +38344607756e693238353007756e693238353107756e693238353207756e693238353307756e693238353407756e69323835 +3507756e693238353607756e693238353707756e693238353807756e693238353907756e693238354107756e693238354207 +756e693238354307756e693238354407756e693238354507756e693238354607756e693238363007756e693238363107756e +693238363207756e693238363307756e693238363407756e693238363507756e693238363607756e693238363707756e6932 +38363807756e693238363907756e693238364107756e693238364207756e693238364307756e693238364407756e69323836 +4507756e693238364607756e693238373007756e693238373107756e693238373207756e693238373307756e693238373407 +756e693238373507756e693238373607756e693238373707756e693238373807756e693238373907756e693238374107756e +693238374207756e693238374307756e693238374407756e693238374507756e693238374607756e693238383007756e6932 +38383107756e693238383207756e693238383307756e693238383407756e693238383507756e693238383607756e69323838 +3707756e693238383807756e693238383907756e693238384107756e693238384207756e693238384307756e693238384407 +756e693238384507756e693238384607756e693238393007756e693238393107756e693238393207756e693238393307756e +693238393407756e693238393507756e693238393607756e693238393707756e693238393807756e693238393907756e6932 +38394107756e693238394207756e693238394307756e693238394407756e693238394507756e693238394607756e69323841 +3007756e693238413107756e693238413207756e693238413307756e693238413407756e693238413507756e693238413607 +756e693238413707756e693238413807756e693238413907756e693238414107756e693238414207756e693238414307756e +693238414407756e693238414507756e693238414607756e693238423007756e693238423107756e693238423207756e6932 +38423307756e693238423407756e693238423507756e693238423607756e693238423707756e693238423807756e69323842 +3907756e693238424107756e693238424207756e693238424307756e693238424407756e693238424507756e693238424607 +756e693238433007756e693238433107756e693238433207756e693238433307756e693238433407756e693238433507756e +693238433607756e693238433707756e693238433807756e693238433907756e693238434107756e693238434207756e6932 +38434307756e693238434407756e693238434507756e693238434607756e693238443007756e693238443107756e69323844 +3207756e693238443307756e693238443407756e693238443507756e693238443607756e693238443707756e693238443807 +756e693238443907756e693238444107756e693238444207756e693238444307756e693238444407756e693238444507756e +693238444607756e693238453007756e693238453107756e693238453207756e693238453307756e693238453407756e6932 +38453507756e693238453607756e693238453707756e693238453807756e693238453907756e693238454107756e69323845 +4207756e693238454307756e693238454407756e693238454507756e693238454607756e693238463007756e693238463107 +756e693238463207756e693238463307756e693238463407756e693238463507756e693238463607756e693238463707756e +693238463807756e693238463907756e693238464107756e693238464207756e693238464307756e693238464407756e6932 +38464507756e693238464607756e693239303607756e693239303707756e693239304107756e693239304207756e69323934 +3007756e693239343107756e693239383307756e693239383407756e693239434507756e693239434607756e693239443007 +756e693239443107756e693239443207756e693239443307756e693239443407756e693239443507756e693239454207756e +693239464107756e693239464207756e693241303007756e693241303107756e693241303207756e693241304307756e6932 +41304407756e693241304507756e693241304607756e693241313007756e693241313107756e693241313207756e69324131 +3307756e693241313407756e693241313507756e693241313607756e693241313707756e693241313807756e693241313907 +756e693241314107756e693241314207756e693241314307756e693241324607756e693241364107756e693241364207756e +693241374407756e693241374507756e693241374607756e693241383007756e693241383107756e693241383207756e6932 +41383307756e693241383407756e693241383507756e693241383607756e693241383707756e693241383807756e69324138 +3907756e693241384107756e693241384207756e693241384307756e693241384407756e693241384507756e693241384607 +756e693241393007756e693241393107756e693241393207756e693241393307756e693241393407756e693241393507756e +693241393607756e693241393707756e693241393807756e693241393907756e693241394107756e693241394207756e6932 +41394307756e693241394407756e693241394507756e693241394607756e693241413007756e693241414507756e69324141 +4607756e693241423007756e693241423107756e693241423207756e693241423307756e693241423407756e693241423507 +756e693241423607756e693241423707756e693241423807756e693241423907756e693241424107756e693241463907756e +693241464107756e693242303007756e693242303107756e693242303207756e693242303307756e693242303407756e6932 +42303507756e693242303607756e693242303707756e693242303807756e693242303907756e693242304107756e69324230 +4207756e693242304307756e693242304407756e693242304507756e693242304607756e693242313007756e693242313107 +756e693242313207756e693242313307756e693242313407756e693242313507756e693242313607756e693242313707756e +693242313807756e693242313907756e693242314107756e693242314607756e693242323007756e693242323107756e6932 +42323207756e693242323307756e693242323407756e693242353307756e693242353407756e693243363007756e69324336 +3107756e693243363207756e693243363307756e693243363407756e693243363507756e693243363607756e693243363707 +756e693243363807756e693243363907756e693243364107756e693243364207756e693243364307756e693243364407756e +693243364507756e693243364607756e693243373007756e693243373107756e693243373207756e693243373307756e6932 +43373407756e693243373507756e693243373607756e693243373707756e693243373907756e693243374107756e69324337 +4207756e693243374307756e693243374407756e693243374507756e693243374607756e693244303007756e693244303107 +756e693244303207756e693244303307756e693244303407756e693244303507756e693244303607756e693244303707756e +693244303807756e693244303907756e693244304107756e693244304207756e693244304307756e693244304407756e6932 +44304507756e693244304607756e693244313007756e693244313107756e693244313207756e693244313307756e69324431 +3407756e693200><44313507756e693244313607756e693244313707756e693244313807756e693244313907756e69324431 +4107756e693244314207756e693244314307756e693244314407756e693244314507756e693244314607756e693244323007 +756e693244323107756e693244323207756e693244323307756e693244323407756e693244323507756e693244333007756e +693244333107756e693244333207756e693244333307756e693244333407756e693244333507756e693244333607756e6932 +44333707756e693244333807756e693244333907756e693244334107756e693244334207756e693244334307756e69324433 +4407756e693244334507756e693244334607756e693244343007756e693244343107756e693244343207756e693244343307 +756e693244343407756e693244343507756e693244343607756e693244343707756e693244343807756e693244343907756e +693244344107756e693244344207756e693244344307756e693244344407756e693244344507756e693244344607756e6932 +44353007756e693244353107756e693244353207756e693244353307756e693244353407756e693244353507756e69324435 +3607756e693244353707756e693244353807756e693244353907756e693244354107756e693244354207756e693244354307 +756e693244354407756e693244354507756e693244354607756e693244363007756e693244363107756e693244363207756e +693244363307756e693244363407756e693244363507756e693244364607756e693245313807756e693245314607756e6932 +45323207756e693245323307756e693245323407756e693245323507756e693245324507756e693444433007756e69344443 +3107756e693444433207756e693444433307756e693444433407756e693444433507756e693444433607756e693444433707 +756e693444433807756e693444433907756e693444434107756e693444434207756e693444434307756e693444434407756e +693444434507756e693444434607756e693444443007756e693444443107756e693444443207756e693444443307756e6934 +44443407756e693444443507756e693444443607756e693444443707756e693444443807756e693444443907756e69344444 +4107756e693444444207756e693444444307756e693444444407756e693444444507756e693444444607756e693444453007 +756e693444453107756e693444453207756e693444453307756e693444453407756e693444453507756e693444453607756e +693444453707756e693444453807756e693444453907756e693444454107756e693444454207756e693444454307756e6934 +44454407756e693444454507756e693444454607756e693444463007756e693444463107756e693444463207756e69344446 +3307756e693444463407756e693444463507756e693444463607756e693444463707756e693444463807756e693444463907 +756e693444464107756e693444464207756e693444464307756e693444464407756e693444464507756e693444464607756e +694134443007756e694134443107756e694134443207756e694134443307756e694134443407756e694134443507756e6941 +34443607756e694134443707756e694134443807756e694134443907756e694134444107756e694134444207756e69413444 +4307756e694134444407756e694134444507756e694134444607756e694134453007756e694134453107756e694134453207 +756e694134453307756e694134453407756e694134453507756e694134453607756e694134453707756e694134453807756e +694134453907756e694134454107756e694134454207756e694134454307756e694134454407756e694134454507756e6941 +34454607756e694134463007756e694134463107756e694134463207756e694134463307756e694134463407756e69413446 +3507756e694134463607756e694134463707756e694134463807756e694134463907756e694134464107756e694134464207 +756e694134464307756e694134464407756e694134464507756e694134464607756e694136343407756e694136343507756e +694136343607756e694136343707756e694136344307756e694136344407756e694136353007756e694136353107756e6941 +36353407756e694136353507756e694136353607756e694136353707756e694136363207756e694136363307756e69413636 +3407756e694136363507756e694136363607756e694136363707756e694136363807756e694136363907756e694136364107 +756e694136364207756e694136364307756e694136364407756e694136364507756e694136384107756e694136384207756e +694136384307756e694136384407756e694136393407756e694136393507756e694137303807756e694137303907756e6941 +37304107756e694137304207756e694137304307756e694137304407756e694137304507756e694137304607756e69413731 +3007756e694137313107756e694137313207756e694137313307756e694137313407756e694137313507756e694137313607 +756e694137314207756e694137314307756e694137314407756e694137314507756e694137314607756e694137323207756e +694137323307756e694137323407756e694137323507756e694137323607756e694137323707756e694137323807756e6941 +37323907756e694137324107756e694137324207756e694137333007756e694137333107756e694137333207756e69413733 +3307756e694137333407756e694137333507756e694137333607756e694137333707756e694137333807756e694137333907 +756e694137334107756e694137334207756e694137334307756e694137334407756e694137334507756e694137334607756e +694137343007756e694137343107756e694137343607756e694137343707756e694137343807756e694137343907756e6941 +37344107756e694137344207756e694137344507756e694137344607756e694137353007756e694137353107756e69413735 +3207756e694137353307756e694137353607756e694137353707756e694137363407756e694137363507756e694137363607 +756e694137363707756e694137383007756e694137383107756e694137383207756e694137383307756e694137383907756e +694137384107756e694137384207756e694137384307756e694137384407756e694137384507756e694137393007756e6941 +37393107756e694137413007756e694137413107756e694137413207756e694137413307756e694137413407756e69413741 +3507756e694137413607756e694137413707756e694137413807756e694137413907756e694137414107756e694137463807 +756e694137463907756e694137464107756e694137464207756e694137464307756e694137464407756e694137464507756e +694137464609756e69303245352e3509756e69303245362e3509756e69303245372e3509756e69303245382e3509756e6930 +3245392e3509756e69303245352e3409756e69303245362e3409756e69303245372e3409756e69303245382e3409756e6930 +3245392e3409756e69303245352e3309756e69303245362e3309756e69303245372e3309756e69303245382e3309756e6930 +3245392e3309756e69303245352e3209756e69303245362e3209756e69303245372e3209756e69303245382e3209756e6930 +3245392e3209756e69303245352e3109756e69303245362e3109756e69303245372e3109756e69303245382e3109756e6930 +3245392e31047374656d07756e694630303007756e694630303107756e694630303207756e694630303307756e6946343030 +07756e694634303107756e694634303207756e694634303307756e694634303407756e694634303507756e69463430360775 +6e694634303707756e694634303807756e694634303907756e694634304107756e694634304207756e694634304307756e69 +4634304407756e694634304507756e694634304607756e694634313007756e694634313107756e694634313207756e694634 +313307756e694634313407756e694634313507756e694634313607756e694634313707756e694634313807756e6946343139 +07756e694634314107756e694634314207756e694634314307756e694634314407756e694634314507756e69463431460775 +6e694634323007756e694634323107756e694634323207756e694634323307756e694634323407756e694634323507756e69 +4634323607756e694634323807756e694634323907756e694634324107756e694634324207756e694634324307756e694634 +324407756e694634324507756e694634324607756e694634333007756e694634333107756e694634333207756e6946343333 +07756e694634333407756e694634333507756e694634333607756e694634333707756e694634333807756e69463433390775 +6e694634334107756e694634334207756e694634334307756e694634334407756e694634334507756e694634334607756e69 +4634343007756e694634343107756e694636433507756e694642303007756e694642303307756e694642303407756e694642 +303507756e694642303607756e694642313307756e694642313407756e694642313507756e694642313607756e6946423137 +07756e694642314407756e694642314507756e694642314607756e694642323007756e694642323107756e69464232320775 +6e694642323307756e694642323407756e694642323507756e694642323607756e694642323707756e694642323807756e69 +4642323907756e694642324107756e694642324207756e694642324307756e694642324407756e694642324507756e694642 +324607756e694642333007756e694642333107756e694642333207756e694642333307756e694642333407756e6946423335 +07756e694642333607756e694642333807756e694642333907756e694642334107756e694642334207756e69464233430775 +6e694642334507756e694642343007756e694642343107756e694642343307756e694642343407756e694642343607756e69 +4642343707756e694642343807756e694642343907756e694642344107756e694642344207756e694642344307756e694642 +344407756e694642344507756e694642344607756e694642353207756e694642353307756e694642353407756e6946423535 +07756e694642353607756e694642353707756e694642353807756e694642353907756e694642354107756e69464235420775 +6e694642354307756e694642354407756e694642354507756e694642354607756e694642363007756e694642363107756e69 +4642363207756e694642363307756e694642363407756e694642363507756e694642363607756e694642363707756e694642 +363807756e694642363907756e694642364107756e694642364207756e694642364307756e694642364407756e6946423645 +07756e694642364607756e694642373007756e694642373107756e694642373207756e694642373307756e69464237340775 +6e694642373507756e694642373607756e694642373707756e694642373807756e694642373907756e694642374107756e69 +4642374207756e694642374307756e694642374407756e694642374507756e694642374607756e694642383007756e694642 +383107756e694642383207756e694642383307756e694642383407756e694642383507756e694642383607756e6946423837 +07756e694642383807756e694642383907756e694642384107756e694642384207756e694642384307756e69464238440775 +6e694642384507756e694642384607756e694642393007756e694642393107756e694642393207756e694642393307756e69 +4642393407756e694642393507756e694642393607756e694642393707756e694642393807756e694642393907756e694642 +394107756e694642394207756e694642394307756e694642394407756e694642394507756e694642394607756e6946424130 +07756e694642413107756e694642413207756e694642413307756e694642414107756e694642414207756e69464241430775 +6e694642414407756e694642443307756e694642443407756e694642443507756e694642443607756e694642443707756e69 +4642443807756e694642443907756e694642444107756e694642444207756e694642444307756e694642444507756e694642 +444607756e694642453407756e694642453507756e694642453607756e694642453707756e694642453807756e6946424539 +07756e694642464307756e694642464407756e694642464507756e694642464607756e694645303007756e69464530310775 +6e694645303207756e694645303307756e694645303407756e694645303507756e694645303607756e694645303707756e69 +4645303807756e694645303907756e694645304107756e694645304207756e694645304307756e694645304407756e694645 +304507756e694645304607756e694645323007756e694645323107756e694645323207756e694645323307756e6946453730 +07756e694645373107756e694645373207756e694645373307756e694645373407756e694645373607756e69464537370775 +6e694645373807756e694645373907756e694645374107756e694645374207756e694645374307756e694645374407756e69 +4645374507756e694645374607756e694645383007756e694645383107756e694645383207756e694645383307756e694645 +383407756e694645383507756e694645383607756e694645383707756e694645383807756e694645383907756e6946453841 +07756e694645384207756e694645384307756e694645384407756e694645384507756e694645384607756e69464539300775 +6e694645393107756e694645393207756e694645393307756e694645393407756e694645393507756e694645393607756e69 +4645393707756e694645393807756e694645393907756e694645394107756e694645394207756e694645394307756e694645 +394407756e694645394507756e694645394607756e694645413007756e694645413107756e694645413207756e6946454133 +07756e694645413407756e694645413507756e694645413607756e694645413707756e694645413807756e69464541390775 +6e694645414107756e694645414207756e694645414307756e694645414407756e694645414507756e694645414607756e69 +4645423007756e694645423107756e694645423207756e694645423307756e694645423407756e694645423507756e694645 +423607756e694645423707756e694645423807756e694645423907756e694645424107756e694645424207756e6946454243 +07756e694645424407756e694645424507756e694645424607756e694645433007756e694645433107756e69464543320775 +6e694645433307756e694645433407756e694645433507756e694645433607756e694645433707756e694645433807756e69 +4645433907756e694645434107756e694645434207756e694645434307756e694645434407756e694645434507756e694645 +434607756e694645443007756e694645443107756e694645443207756e694645443307756e694645443407756e6946454435 +07756e694645443607756e694645443707756e694645443807756e694645443907756e694645444107756e69464544420775 +6e694645444307756e694645444407756e694645444507756e694645444607756e694645453007756e694645453107756e69 +4645453207756e694645453307756e694645453407756e694645453507756e694645453607756e694645453707756e694645 +453807756e694645453907756e694645454107756e694645454207756e694645454307756e694645454407756e6946454545 +07756e694645454607756e694645463007756e694645463107756e694645463207756e694645463307756e69464546340775 +6e694645463507756e694645463607756e694645463707756e694645463807756e694645463907756e694645464107756e69 +4645464207756e694645464307756e694645464607756e694646463907756e694646464107756e694646464207756e694646 +464307756e694646464406753130333030067531303330310675313033303206753130333033067531303330340675313033 +3035067531303330360675313033303706753130333038067531303330390675313033304106753130333042067531303330 +4306753130333044067531303330450675313033304606753130333130067531303331310675313033313206753130333133 +0675313033313406753130333135067531303331360675313033313706753130333138067531303331390675313033314106 +7531303331420675313033314306753130333144067531303331450675313033323006753130333231067531303332320675 +3130333233067531443330300675314433303106753144333032067531443330330675314433303406753144333035067531 +4433303606753144333037067531443330380675314433303906753144333041067531443330420675314433304306753144 +3330440675314433304506753144333046067531443331300675314433313106753144333132067531443331330675314433 +3134067531443331350675314433313606753144333137067531443331380675314433313906753144333141067531443331 +4206753144333143067531443331440675314433314506753144333146067531443332300675314433323106753144333232 +0675314433323306753144333234067531443332350675314433323606753144333237067531443332380675314433323906 +7531443332410675314433324206753144333243067531443332440675314433324506753144333246067531443333300675 +3144333331067531443333320675314433333306753144333334067531443333350675314433333606753144333337067531 +4433333806753144333339067531443333410675314433334206753144333343067531443333440675314433334506753144 +3333460675314433343006753144333431067531443334320675314433343306753144333434067531443334350675314433 +3436067531443334370675314433343806753144333439067531443334410675314433344206753144333443067531443334 +4406753144333445067531443334460675314433353006753144333531067531443335320675314433353306753144333534 +0675314433353506753144333536067531443533380675314435333906753144353342067531443533430675314435334406 +7531443533450675314435343006753144353431067531443534320675314435343306753144353434067531443534360675 +3144353441067531443534420675314435344306753144353444067531443534450675314435344606753144353530067531 +4435353206753144353533067531443535340675314435353506753144353536067531443535370675314435353806753144 +3535390675314435354106753144353542067531443535430675314435354406753144353545067531443535460675314435 +3630067531443536310675314435363206753144353633067531443536340675314435363506753144353636067531443536 +3706753144353638067531443536390675314435364106753144353642067531443541300675314435413106753144354132 +0675314435413306753144354134067531443541350675314435413606753144354137067531443541380675314435413906 +7531443541410675314435414206753144354143067531443541440675314435414506753144354146067531443542300675 +3144354231067531443542320675314435423306753144354234067531443542350675314435423606753144354237067531 +4435423806753144354239067531443542410675314435424206753144354243067531443542440675314435424506753144 +3542460675314435433006753144354331067531443543320675314435433306753144354334067531443543350675314435 +4336067531443543370675314435433806753144354339067531443543410675314435434206753144354343067531443543 +4406753144354345067531443543460675314435443006753144354431067531443544320675314435443306753144374438 +0675314437443906753144374441067531443744420675314437444306753144374444067531443744450675314437444606 +7531443745300675314437453106753144374532067531443745330675314437453406753144374535067531443745360675 +3144374537067531443745380675314437453906753144374541067531443745420675314545303006753145453031067531 +4545303206753145453033067531454530350675314545303606753145453037067531454530380675314545303906753145 +4530410675314545304206753145453043067531454530440675314545304506753145453046067531454531300675314545 +3131067531454531320675314545313306753145453134067531454531350675314545313606753145453137067531454531 +3806753145453139067531454531410675314545314206753145453143067531454531440675314545314506753145453146 +0675314545323106753145453232067531454532340675314545323706753145453239067531454532410675314545324206 +7531454532430675314545324406753145453245067531454532460675314545333006753145453331067531454533320675 +3145453334067531454533350675314545333606753145453337067531454533390675314545334206753145453631067531 +4545363206753145453634067531454536370675314545363806753145453639067531454536410675314545364306753145 +4536440675314545364506753145453646067531454537300675314545373106753145453732067531454537340675314545 +3735067531454537360675314545373706753145453739067531454537410675314545374206753145453743067531454537 +4506753146303330067531463033310675314630333206753146303333067531463033340675314630333506753146303336 +0675314630333706753146303338067531463033390675314630334106753146303342067531463033430675314630334406 +7531463033450675314630334606753146303430067531463034310675314630343206753146303433067531463034340675 +3146303435067531463034360675314630343706753146303438067531463034390675314630344106753146303442067531 +4630344306753146303444067531463034450675314630344606753146303530067531463035310675314630353206753146 +3035330675314630353406753146303535067531463035360675314630353706753146303538067531463035390675314630 +3541067531463035420675314630354306753146303544067531463035450675314630354606753146303630067531463036 +3106753146303632067531463036330675314630363406753146303635067531463036360675314630363706753146303638 +0675314630363906753146303641067531463036420675314630364306753146303644067531463036450675314630364606 +7531463037300675314630373106753146303732067531463037330675314630373406753146303735067531463037360675 +3146303737067531463037380675314630373906753146303741067531463037420675314630374306753146303744067531 +4630374506753146303746067531463038300675314630383106753146303832067531463038330675314630383406753146 +3038350675314630383606753146303837067531463038380675314630383906753146303841067531463038420675314630 +3843067531463038440675314630384506753146303846067531463039300675314630393106753146303932067531463039 +3306753146304130067531463041310675314630413206753146304133067531463041340675314630413506753146304136 +0675314630413706753146304138067531463041390675314630414106753146304142067531463041430675314630414406 +7531463041450675314630423106753146304232067531463042330675314630423406753146304235067531463042360675 +3146304237067531463042380675314630423906753146304241067531463042420675314630424306753146304244067531 +4630424506753146304331067531463043320675314630433306753146304334067531463043350675314630433606753146 +3043370675314630433806753146304339067531463043410675314630434206753146304343067531463043440675314630 +4345067531463043460675314630443106753146304432067531463044330675314630443406753146304435067531463044 +3606753146304437067531463044380675314630443906753146304441067531463044420675314630444306753146304444 +0675314630444506753146304446067531463432440675314634324506753146343331067531463433350675314636303006 +7531463630310675314636303206753146363033067531463630340675314636303506753146363036067531463630370675 +3146363038067531463630390675314636304106753146363042067531463630430675314636304406753146363045067531 +4636304606753146363130067531463631310675314636313206753146363133067531463631340675314636313506753146 +3631360675314636313706753146363138067531463631390675314636314106753146363142067531463631430675314636 +3144067531463631450675314636314606753146363230067531463632310675314636323206753146363233067531463632 +3506753146363236067531463632370675314636323806753146363239067531463632410675314636324206753146363244 +0675314636324506753146363246067531463633300675314636333106753146363332067531463633330675314636333406 +7531463633350675314636333606753146363337067531463633380675314636333906753146363341067531463633420675 +31463633430675314636334406753146363345067531463633460675314636343009646c4c746361726f6e08446965726573 +69730541637574650554696c64650547726176650a43697263756d666c6578054361726f6e0c756e69303331312e63617365 +05427265766509446f74616363656e740c48756e676172756d6c6175740b446f75626c6567726176650a6172616269635f64 +6f740c6172616269635f32646f74730c6172616269635f33646f74730e6172616269635f33646f74735f610e617261626963 +5f32646f74735f610c6172616269635f34646f74730c756e69303636452e66696e610c756e69303636452e696e69740c756e +69303636452e6d6564690c756e69303641312e66696e610c756e69303641312e696e69740c756e69303641312e6d6564690c +756e69303636462e66696e610c756e69303636462e696e69740c756e69303636462e6d6564690c756e69303642412e696e69 +740c756e69303642412e6d6564690b6172616269635f72696e670c756e69303637432e66696e610c756e69303637432e696e +69740c756e69303637432e6d6564690c756e69303637442e66696e610c756e69303637442e696e69740c756e69303637442e +6d6564690c756e69303638312e66696e610c756e69303638312e696e69740c756e69303638312e6d6564690c756e69303638 +322e66696e610c756e69303638322e696e69740c756e69303638322e6d6564690c756e69303638352e66696e610c756e6930 +3638352e696e69740c756e69303638352e6d6564690c756e69303642462e66696e610c756e69303642462e696e69740c756e +69303642462e6d6564690e6172616269635f6761665f62617207456e672e616c740f756e69303236382e646f746c6573730f +756e69303239442e646f746c6573730b756e6930333038303330340b756e6930333034303330380b756e6930333037303330 +340b756e6930333038303330310b756e6930333038303330300b756e6930333034303330310b756e6930333034303330300b +756e6930333033303330340b756e69303330383033304300b8028040fffbfe03fa1403f92503f83203f79603f60e03f5fe03 +f4fe03f32503f20e03f19603f02503ef8a4105effe03ee9603ed9603ecfa03ebfa03eafe03e93a03e84203e7fe03e63203e5 +e45305e59603e48a4105e45303e3e22f05e3fa03e22f03e1fe03e0fe03df3203de1403dd9603dcfe03db1203da7d03d9bb03 +d8fe03d68a4105d67d03d5d44705d57d03d44703d3d21b05d3fe03d21b03d1fe03d0fe03cffe03cefe03cd9603cccb1e05cc +fe03cb1e03ca3203c9fe03c6851105c61c03c51603c4fe03c3fe03c2fe03c1fe03c0fe03bffe03befe03bdfe03bcfe03bbfe +03ba1103b9862505b9fe03b8b7bb05b8fe03b7b65d05b7bb03b78004b6b52505b65d40ff03b64004b52503b4fe03b39603b2 +fe03b1fe03b0fe03affe03ae6403ad0e03acab2505ac6403abaa1205ab2503aa1203a98a4105a9fa03a8fe03a7fe03a6fe03 +a51203a4fe03a3a20e05a33203a20e03a16403a08a4105a096039ffe039e9d0c059efe039d0c039c9b19059c64039b9a1005 +9b19039a1003990a0398fe0397960d0597fe03960d03958a410595960394930e05942803930e0392fa039190bb0591fe0390 +8f5d0590bb039080048f8e25058f5d038f40048e25038dfe038c8b2e058cfe038b2e038a8625058a410389880b0589140388 +0b03878625058764038685110586250385110384fe038382110583fe0382110381fe0380fe037ffe0340ff7e7d7d057efe03 +7d7d037c64037b5415057b25037afe0379fe03780e03770c03760a0375fe0374fa0373fa0372fa0371fa0370fe036ffe036e +fe036c21036bfe036a1142056a530369fe03687d036711420566fe0365fe0364fe0363fe0362fe03613a0360fa035e0c035d +fe035bfe035afe0359580a0559fa03580a035716190557320356fe035554150555420354150353011005531803521403514a +130551fe03500b034ffe034e4d10054efe034d10034cfe034b4a13054bfe034a4910054a1303491d0d05491003480d0347fe +0346960345960344fe0343022d0543fa0342bb03414b0340fe033ffe033e3d12053e14033d3c0f053d12033c3b0d053c40ff +0f033b0d033afe0339fe033837140538fa033736100537140336350b05361003350b03341e03330d0332310b0532fe03310b +03302f0b05300d032f0b032e2d09052e10032d09032c32032b2a25052b64032a2912052a2503291203282725052841032725 +0326250b05260f03250b0324fe0323fe03220f03210110052112032064031ffa031e1d0d051e64031d0d031c1142051cfe03 +1bfa031a42031911420519fe031864031716190517fe031601100516190315fe0314fe0313fe031211420512fe0311022d05 +114203107d030f64030efe030d0c16050dfe030c0110050c16030bfe030a100309fe0308022d0508fe030714030664030401 +100504fe03401503022d0503fe0302011005022d0301100300fe0301b80164858d012b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b00 +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b1d00>]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-1 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 5862 dict dup begin +/.notdef 0 def +/.null 1 def +/nonmarkingreturn 2 def +/space 3 def +/exclam 4 def +/quotedbl 5 def +/numbersign 6 def +/dollar 7 def +/percent 8 def +/ampersand 9 def +/quotesingle 10 def +/parenleft 11 def +/parenright 12 def +/asterisk 13 def +/plus 14 def +/comma 15 def +/hyphen 16 def +/period 17 def +/slash 18 def +/zero 19 def +/one 20 def +/two 21 def +/three 22 def +/four 23 def +/five 24 def +/six 25 def +/seven 26 def +/eight 27 def +/nine 28 def +/colon 29 def +/semicolon 30 def +/less 31 def +/equal 32 def +/greater 33 def +/question 34 def +/at 35 def +/A 36 def +/B 37 def +/C 38 def +/D 39 def +/E 40 def +/F 41 def +/G 42 def +/H 43 def +/I 44 def +/J 45 def +/K 46 def +/L 47 def +/M 48 def +/N 49 def +/O 50 def +/P 51 def +/Q 52 def +/R 53 def +/S 54 def +/T 55 def +/U 56 def +/V 57 def +/W 58 def +/X 59 def +/Y 60 def +/Z 61 def +/bracketleft 62 def +/backslash 63 def +/bracketright 64 def +/asciicircum 65 def +/underscore 66 def +/grave 67 def +/a 68 def +/b 69 def +/c 70 def +/d 71 def +/e 72 def +/f 73 def +/g 74 def +/h 75 def +/i 76 def +/j 77 def +/k 78 def +/l 79 def +/m 80 def +/n 81 def +/o 82 def +/p 83 def +/q 84 def +/r 85 def +/s 86 def +/t 87 def +/u 88 def +/v 89 def +/w 90 def +/x 91 def +/y 92 def +/z 93 def +/braceleft 94 def +/bar 95 def +/braceright 96 def +/asciitilde 97 def +/nonbreakingspace 98 def +/exclamdown 99 def +/cent 100 def +/sterling 101 def +/currency 102 def +/yen 103 def +/brokenbar 104 def +/section 105 def +/dieresis 106 def +/copyright 107 def +/ordfeminine 108 def +/guillemotleft 109 def +/logicalnot 110 def +/sfthyphen 111 def +/registered 112 def +/macron 113 def +/degree 114 def +/plusminus 115 def +/twosuperior 116 def +/threesuperior 117 def +/acute 118 def +/mu 119 def +/paragraph 120 def +/periodcentered 121 def +/cedilla 122 def +/onesuperior 123 def +/ordmasculine 124 def +/guillemotright 125 def +/onequarter 126 def +/onehalf 127 def +/threequarters 128 def +/questiondown 129 def +/Agrave 130 def +/Aacute 131 def +/Acircumflex 132 def +/Atilde 133 def +/Adieresis 134 def +/Aring 135 def +/AE 136 def +/Ccedilla 137 def +/Egrave 138 def +/Eacute 139 def +/Ecircumflex 140 def +/Edieresis 141 def +/Igrave 142 def +/Iacute 143 def +/Icircumflex 144 def +/Idieresis 145 def +/Eth 146 def +/Ntilde 147 def +/Ograve 148 def +/Oacute 149 def +/Ocircumflex 150 def +/Otilde 151 def +/Odieresis 152 def +/multiply 153 def +/Oslash 154 def +/Ugrave 155 def +/Uacute 156 def +/Ucircumflex 157 def +/Udieresis 158 def +/Yacute 159 def +/Thorn 160 def +/germandbls 161 def +/agrave 162 def +/aacute 163 def +/acircumflex 164 def +/atilde 165 def +/adieresis 166 def +/aring 167 def +/ae 168 def +/ccedilla 169 def +/egrave 170 def +/eacute 171 def +/ecircumflex 172 def +/edieresis 173 def +/igrave 174 def +/iacute 175 def +/icircumflex 176 def +/idieresis 177 def +/eth 178 def +/ntilde 179 def +/ograve 180 def +/oacute 181 def +/ocircumflex 182 def +/otilde 183 def +/odieresis 184 def +/divide 185 def +/oslash 186 def +/ugrave 187 def +/uacute 188 def +/ucircumflex 189 def +/udieresis 190 def +/yacute 191 def +/thorn 192 def +/ydieresis 193 def +/Amacron 194 def +/amacron 195 def +/Abreve 196 def +/abreve 197 def +/Aogonek 198 def +/aogonek 199 def +/Cacute 200 def +/cacute 201 def +/Ccircumflex 202 def +/ccircumflex 203 def +/Cdotaccent 204 def +/cdotaccent 205 def +/Ccaron 206 def +/ccaron 207 def +/Dcaron 208 def +/dcaron 209 def +/Dcroat 210 def +/dcroat 211 def +/Emacron 212 def +/emacron 213 def +/Ebreve 214 def +/ebreve 215 def +/Edotaccent 216 def +/edotaccent 217 def +/Eogonek 218 def +/eogonek 219 def +/Ecaron 220 def +/ecaron 221 def +/Gcircumflex 222 def +/gcircumflex 223 def +/Gbreve 224 def +/gbreve 225 def +/Gdotaccent 226 def +/gdotaccent 227 def +/Gcommaaccent 228 def +/gcommaaccent 229 def +/Hcircumflex 230 def +/hcircumflex 231 def +/Hbar 232 def +/hbar 233 def +/Itilde 234 def +/itilde 235 def +/Imacron 236 def +/imacron 237 def +/Ibreve 238 def +/ibreve 239 def +/Iogonek 240 def +/iogonek 241 def +/Idotaccent 242 def +/dotlessi 243 def +/IJ 244 def +/ij 245 def +/Jcircumflex 246 def +/jcircumflex 247 def +/Kcommaaccent 248 def +/kcommaaccent 249 def +/kgreenlandic 250 def +/Lacute 251 def +/lacute 252 def +/Lcommaaccent 253 def +/lcommaaccent 254 def +/Lcaron 255 def +/lcaron 256 def +/Ldot 257 def +/ldot 258 def +/Lslash 259 def +/lslash 260 def +/Nacute 261 def +/nacute 262 def +/Ncommaaccent 263 def +/ncommaaccent 264 def +/Ncaron 265 def +/ncaron 266 def +/napostrophe 267 def +/Eng 268 def +/eng 269 def +/Omacron 270 def +/omacron 271 def +/Obreve 272 def +/obreve 273 def +/Ohungarumlaut 274 def +/ohungarumlaut 275 def +/OE 276 def +/oe 277 def +/Racute 278 def +/racute 279 def +/Rcommaaccent 280 def +/rcommaaccent 281 def +/Rcaron 282 def +/rcaron 283 def +/Sacute 284 def +/sacute 285 def +/Scircumflex 286 def +/scircumflex 287 def +/Scedilla 288 def +/scedilla 289 def +/Scaron 290 def +/scaron 291 def +/Tcommaaccent 292 def +/tcommaaccent 293 def +/Tcaron 294 def +/tcaron 295 def +/Tbar 296 def +/tbar 297 def +/Utilde 298 def +/utilde 299 def +/Umacron 300 def +/umacron 301 def +/Ubreve 302 def +/ubreve 303 def +/Uring 304 def +/uring 305 def +/Uhungarumlaut 306 def +/uhungarumlaut 307 def +/Uogonek 308 def +/uogonek 309 def +/Wcircumflex 310 def +/wcircumflex 311 def +/Ycircumflex 312 def +/ycircumflex 313 def +/Ydieresis 314 def +/Zacute 315 def +/zacute 316 def +/Zdotaccent 317 def +/zdotaccent 318 def +/Zcaron 319 def +/zcaron 320 def +/longs 321 def +/uni0180 322 def +/uni0181 323 def +/uni0182 324 def +/uni0183 325 def +/uni0184 326 def +/uni0185 327 def +/uni0186 328 def +/uni0187 329 def +/uni0188 330 def +/uni0189 331 def +/uni018A 332 def +/uni018B 333 def +/uni018C 334 def +/uni018D 335 def +/uni018E 336 def +/uni018F 337 def +/uni0190 338 def +/uni0191 339 def +/florin 340 def +/uni0193 341 def +/uni0194 342 def +/uni0195 343 def +/uni0196 344 def +/uni0197 345 def +/uni0198 346 def +/uni0199 347 def +/uni019A 348 def +/uni019B 349 def +/uni019C 350 def +/uni019D 351 def +/uni019E 352 def +/uni019F 353 def +/Ohorn 354 def +/ohorn 355 def +/uni01A2 356 def +/uni01A3 357 def +/uni01A4 358 def +/uni01A5 359 def +/uni01A6 360 def +/uni01A7 361 def +/uni01A8 362 def +/uni01A9 363 def +/uni01AA 364 def +/uni01AB 365 def +/uni01AC 366 def +/uni01AD 367 def +/uni01AE 368 def +/Uhorn 369 def +/uhorn 370 def +/uni01B1 371 def +/uni01B2 372 def +/uni01B3 373 def +/uni01B4 374 def +/uni01B5 375 def +/uni01B6 376 def +/uni01B7 377 def +/uni01B8 378 def +/uni01B9 379 def +/uni01BA 380 def +/uni01BB 381 def +/uni01BC 382 def +/uni01BD 383 def +/uni01BE 384 def +/uni01BF 385 def +/uni01C0 386 def +/uni01C1 387 def +/uni01C2 388 def +/uni01C3 389 def +/uni01C4 390 def +/uni01C5 391 def +/uni01C6 392 def +/uni01C7 393 def +/uni01C8 394 def +/uni01C9 395 def +/uni01CA 396 def +/uni01CB 397 def +/uni01CC 398 def +/uni01CD 399 def +/uni01CE 400 def +/uni01CF 401 def +/uni01D0 402 def +/uni01D1 403 def +/uni01D2 404 def +/uni01D3 405 def +/uni01D4 406 def +/uni01D5 407 def +/uni01D6 408 def +/uni01D7 409 def +/uni01D8 410 def +/uni01D9 411 def +/uni01DA 412 def +/uni01DB 413 def +/uni01DC 414 def +/uni01DD 415 def +/uni01DE 416 def +/uni01DF 417 def +/uni01E0 418 def +/uni01E1 419 def +/uni01E2 420 def +/uni01E3 421 def +/uni01E4 422 def +/uni01E5 423 def +/Gcaron 424 def +/gcaron 425 def +/uni01E8 426 def +/uni01E9 427 def +/uni01EA 428 def +/uni01EB 429 def +/uni01EC 430 def +/uni01ED 431 def +/uni01EE 432 def +/uni01EF 433 def +/uni01F0 434 def +/uni01F1 435 def +/uni01F2 436 def +/uni01F3 437 def +/uni01F4 438 def +/uni01F5 439 def +/uni01F6 440 def +/uni01F7 441 def +/uni01F8 442 def +/uni01F9 443 def +/Aringacute 444 def +/aringacute 445 def +/AEacute 446 def +/aeacute 447 def +/Oslashacute 448 def +/oslashacute 449 def +/uni0200 450 def +/uni0201 451 def +/uni0202 452 def +/uni0203 453 def +/uni0204 454 def +/uni0205 455 def +/uni0206 456 def +/uni0207 457 def +/uni0208 458 def +/uni0209 459 def +/uni020A 460 def +/uni020B 461 def +/uni020C 462 def +/uni020D 463 def +/uni020E 464 def +/uni020F 465 def +/uni0210 466 def +/uni0211 467 def +/uni0212 468 def +/uni0213 469 def +/uni0214 470 def +/uni0215 471 def +/uni0216 472 def +/uni0217 473 def +/Scommaaccent 474 def +/scommaaccent 475 def +/uni021A 476 def +/uni021B 477 def +/uni021C 478 def +/uni021D 479 def +/uni021E 480 def +/uni021F 481 def +/uni0220 482 def +/uni0221 483 def +/uni0222 484 def +/uni0223 485 def +/uni0224 486 def +/uni0225 487 def +/uni0226 488 def +/uni0227 489 def +/uni0228 490 def +/uni0229 491 def +/uni022A 492 def +/uni022B 493 def +/uni022C 494 def +/uni022D 495 def +/uni022E 496 def +/uni022F 497 def +/uni0230 498 def +/uni0231 499 def +/uni0232 500 def +/uni0233 501 def +/uni0234 502 def +/uni0235 503 def +/uni0236 504 def +/dotlessj 505 def +/uni0238 506 def +/uni0239 507 def +/uni023A 508 def +/uni023B 509 def +/uni023C 510 def +/uni023D 511 def +/uni023E 512 def +/uni023F 513 def +/uni0240 514 def +/uni0241 515 def +/uni0242 516 def +/uni0243 517 def +/uni0244 518 def +/uni0245 519 def +/uni0246 520 def +/uni0247 521 def +/uni0248 522 def +/uni0249 523 def +/uni024A 524 def +/uni024B 525 def +/uni024C 526 def +/uni024D 527 def +/uni024E 528 def +/uni024F 529 def +/uni0250 530 def +/uni0251 531 def +/uni0252 532 def +/uni0253 533 def +/uni0254 534 def +/uni0255 535 def +/uni0256 536 def +/uni0257 537 def +/uni0258 538 def +/uni0259 539 def +/uni025A 540 def +/uni025B 541 def +/uni025C 542 def +/uni025D 543 def +/uni025E 544 def +/uni025F 545 def +/uni0260 546 def +/uni0261 547 def +/uni0262 548 def +/uni0263 549 def +/uni0264 550 def +/uni0265 551 def +/uni0266 552 def +/uni0267 553 def +/uni0268 554 def +/uni0269 555 def +/uni026A 556 def +/uni026B 557 def +/uni026C 558 def +/uni026D 559 def +/uni026E 560 def +/uni026F 561 def +/uni0270 562 def +/uni0271 563 def +/uni0272 564 def +/uni0273 565 def +/uni0274 566 def +/uni0275 567 def +/uni0276 568 def +/uni0277 569 def +/uni0278 570 def +/uni0279 571 def +/uni027A 572 def +/uni027B 573 def +/uni027C 574 def +/uni027D 575 def +/uni027E 576 def +/uni027F 577 def +/uni0280 578 def +/uni0281 579 def +/uni0282 580 def +/uni0283 581 def +/uni0284 582 def +/uni0285 583 def +/uni0286 584 def +/uni0287 585 def +/uni0288 586 def +/uni0289 587 def +/uni028A 588 def +/uni028B 589 def +/uni028C 590 def +/uni028D 591 def +/uni028E 592 def +/uni028F 593 def +/uni0290 594 def +/uni0291 595 def +/uni0292 596 def +/uni0293 597 def +/uni0294 598 def +/uni0295 599 def +/uni0296 600 def +/uni0297 601 def +/uni0298 602 def +/uni0299 603 def +/uni029A 604 def +/uni029B 605 def +/uni029C 606 def +/uni029D 607 def +/uni029E 608 def +/uni029F 609 def +/uni02A0 610 def +/uni02A1 611 def +/uni02A2 612 def +/uni02A3 613 def +/uni02A4 614 def +/uni02A5 615 def +/uni02A6 616 def +/uni02A7 617 def +/uni02A8 618 def +/uni02A9 619 def +/uni02AA 620 def +/uni02AB 621 def +/uni02AC 622 def +/uni02AD 623 def +/uni02AE 624 def +/uni02AF 625 def +/uni02B0 626 def +/uni02B1 627 def +/uni02B2 628 def +/uni02B3 629 def +/uni02B4 630 def +/uni02B5 631 def +/uni02B6 632 def +/uni02B7 633 def +/uni02B8 634 def +/uni02B9 635 def +/uni02BA 636 def +/uni02BB 637 def +/uni02BC 638 def +/uni02BD 639 def +/uni02BE 640 def +/uni02BF 641 def +/uni02C0 642 def +/uni02C1 643 def +/uni02C2 644 def +/uni02C3 645 def +/uni02C4 646 def +/uni02C5 647 def +/circumflex 648 def +/caron 649 def +/uni02C8 650 def +/uni02C9 651 def +/uni02CA 652 def +/uni02CB 653 def +/uni02CC 654 def +/uni02CD 655 def +/uni02CE 656 def +/uni02CF 657 def +/uni02D0 658 def +/uni02D1 659 def +/uni02D2 660 def +/uni02D3 661 def +/uni02D4 662 def +/uni02D5 663 def +/uni02D6 664 def +/uni02D7 665 def +/breve 666 def +/dotaccent 667 def +/ring 668 def +/ogonek 669 def +/tilde 670 def +/hungarumlaut 671 def +/uni02DE 672 def +/uni02DF 673 def +/uni02E0 674 def +/uni02E1 675 def +/uni02E2 676 def +/uni02E3 677 def +/uni02E4 678 def +/uni02E5 679 def +/uni02E6 680 def +/uni02E7 681 def +/uni02E8 682 def +/uni02E9 683 def +/uni02EC 684 def +/uni02ED 685 def +/uni02EE 686 def +/uni02F3 687 def +/uni02F7 688 def +/gravecomb 689 def +/acutecomb 690 def +/uni0302 691 def +/tildecomb 692 def +/uni0304 693 def +/uni0305 694 def +/uni0306 695 def +/uni0307 696 def +/uni0308 697 def +/hookabovecomb 698 def +/uni030A 699 def +/uni030B 700 def +/uni030C 701 def +/uni030D 702 def +/uni030E 703 def +/uni030F 704 def +/uni0310 705 def +/uni0311 706 def +/uni0312 707 def +/uni0313 708 def +/uni0314 709 def +/uni0315 710 def +/uni0316 711 def +/uni0317 712 def +/uni0318 713 def +/uni0319 714 def +/uni031A 715 def +/uni031B 716 def +/uni031C 717 def +/uni031D 718 def +/uni031E 719 def +/uni031F 720 def +/uni0320 721 def +/uni0321 722 def +/uni0322 723 def +/dotbelowcomb 724 def +/uni0324 725 def +/uni0325 726 def +/uni0326 727 def +/uni0327 728 def +/uni0328 729 def +/uni0329 730 def +/uni032A 731 def +/uni032B 732 def +/uni032C 733 def +/uni032D 734 def +/uni032E 735 def +/uni032F 736 def +/uni0330 737 def +/uni0331 738 def +/uni0332 739 def +/uni0333 740 def +/uni0334 741 def +/uni0335 742 def +/uni0336 743 def +/uni0337 744 def +/uni0338 745 def +/uni0339 746 def +/uni033A 747 def +/uni033B 748 def +/uni033C 749 def +/uni033D 750 def +/uni033E 751 def +/uni033F 752 def +/uni0340 753 def +/uni0341 754 def +/uni0342 755 def +/uni0343 756 def +/uni0344 757 def +/uni0345 758 def +/uni0346 759 def +/uni0347 760 def +/uni0348 761 def +/uni0349 762 def +/uni034A 763 def +/uni034B 764 def +/uni034C 765 def +/uni034D 766 def +/uni034E 767 def +/uni034F 768 def +/uni0351 769 def +/uni0352 770 def +/uni0353 771 def +/uni0357 772 def +/uni0358 773 def +/uni035A 774 def +/uni035C 775 def +/uni035D 776 def +/uni035E 777 def +/uni035F 778 def +/uni0360 779 def +/uni0361 780 def +/uni0362 781 def +/uni0370 782 def +/uni0371 783 def +/uni0372 784 def +/uni0373 785 def +/uni0374 786 def +/uni0375 787 def +/uni0376 788 def +/uni0377 789 def +/uni037A 790 def +/uni037B 791 def +/uni037C 792 def +/uni037D 793 def +/uni037E 794 def +/tonos 795 def +/dieresistonos 796 def +/Alphatonos 797 def +/anoteleia 798 def +/Epsilontonos 799 def +/Etatonos 800 def +/Iotatonos 801 def +/Omicrontonos 802 def +/Upsilontonos 803 def +/Omegatonos 804 def +/iotadieresistonos 805 def +/Alpha 806 def +/Beta 807 def +/Gamma 808 def +/uni0394 809 def +/Epsilon 810 def +/Zeta 811 def +/Eta 812 def +/Theta 813 def +/Iota 814 def +/Kappa 815 def +/Lambda 816 def +/Mu 817 def +/Nu 818 def +/Xi 819 def +/Omicron 820 def +/Pi 821 def +/Rho 822 def +/Sigma 823 def +/Tau 824 def +/Upsilon 825 def +/Phi 826 def +/Chi 827 def +/Psi 828 def +/Omega 829 def +/Iotadieresis 830 def +/Upsilondieresis 831 def +/alphatonos 832 def +/epsilontonos 833 def +/etatonos 834 def +/iotatonos 835 def +/upsilondieresistonos 836 def +/alpha 837 def +/beta 838 def +/gamma 839 def +/delta 840 def +/epsilon 841 def +/zeta 842 def +/eta 843 def +/theta 844 def +/iota 845 def +/kappa 846 def +/lambda 847 def +/uni03BC 848 def +/nu 849 def +/xi 850 def +/omicron 851 def +/pi 852 def +/rho 853 def +/sigma1 854 def +/sigma 855 def +/tau 856 def +/upsilon 857 def +/phi 858 def +/chi 859 def +/psi 860 def +/omega 861 def +/iotadieresis 862 def +/upsilondieresis 863 def +/omicrontonos 864 def +/upsilontonos 865 def +/omegatonos 866 def +/uni03CF 867 def +/uni03D0 868 def +/theta1 869 def +/Upsilon1 870 def +/uni03D3 871 def +/uni03D4 872 def +/phi1 873 def +/omega1 874 def +/uni03D7 875 def +/uni03D8 876 def +/uni03D9 877 def +/uni03DA 878 def +/uni03DB 879 def +/uni03DC 880 def +/uni03DD 881 def +/uni03DE 882 def +/uni03DF 883 def +/uni03E0 884 def +/uni03E1 885 def +/uni03E2 886 def +/uni03E3 887 def +/uni03E4 888 def +/uni03E5 889 def +/uni03E6 890 def +/uni03E7 891 def +/uni03E8 892 def +/uni03E9 893 def +/uni03EA 894 def +/uni03EB 895 def +/uni03EC 896 def +/uni03ED 897 def +/uni03EE 898 def +/uni03EF 899 def +/uni03F0 900 def +/uni03F1 901 def +/uni03F2 902 def +/uni03F3 903 def +/uni03F4 904 def +/uni03F5 905 def +/uni03F6 906 def +/uni03F7 907 def +/uni03F8 908 def +/uni03F9 909 def +/uni03FA 910 def +/uni03FB 911 def +/uni03FC 912 def +/uni03FD 913 def +/uni03FE 914 def +/uni03FF 915 def +/uni0400 916 def +/uni0401 917 def +/uni0402 918 def +/uni0403 919 def +/uni0404 920 def +/uni0405 921 def +/uni0406 922 def +/uni0407 923 def +/uni0408 924 def +/uni0409 925 def +/uni040A 926 def +/uni040B 927 def +/uni040C 928 def +/uni040D 929 def +/uni040E 930 def +/uni040F 931 def +/uni0410 932 def +/uni0411 933 def +/uni0412 934 def +/uni0413 935 def +/uni0414 936 def +/uni0415 937 def +/uni0416 938 def +/uni0417 939 def +/uni0418 940 def +/uni0419 941 def +/uni041A 942 def +/uni041B 943 def +/uni041C 944 def +/uni041D 945 def +/uni041E 946 def +/uni041F 947 def +/uni0420 948 def +/uni0421 949 def +/uni0422 950 def +/uni0423 951 def +/uni0424 952 def +/uni0425 953 def +/uni0426 954 def +/uni0427 955 def +/uni0428 956 def +/uni0429 957 def +/uni042A 958 def +/uni042B 959 def +/uni042C 960 def +/uni042D 961 def +/uni042E 962 def +/uni042F 963 def +/uni0430 964 def +/uni0431 965 def +/uni0432 966 def +/uni0433 967 def +/uni0434 968 def +/uni0435 969 def +/uni0436 970 def +/uni0437 971 def +/uni0438 972 def +/uni0439 973 def +/uni043A 974 def +/uni043B 975 def +/uni043C 976 def +/uni043D 977 def +/uni043E 978 def +/uni043F 979 def +/uni0440 980 def +/uni0441 981 def +/uni0442 982 def +/uni0443 983 def +/uni0444 984 def +/uni0445 985 def +/uni0446 986 def +/uni0447 987 def +/uni0448 988 def +/uni0449 989 def +/uni044A 990 def +/uni044B 991 def +/uni044C 992 def +/uni044D 993 def +/uni044E 994 def +/uni044F 995 def +/uni0450 996 def +/uni0451 997 def +/uni0452 998 def +/uni0453 999 def +/uni0454 1000 def +/uni0455 1001 def +/uni0456 1002 def +/uni0457 1003 def +/uni0458 1004 def +/uni0459 1005 def +/uni045A 1006 def +/uni045B 1007 def +/uni045C 1008 def +/uni045D 1009 def +/uni045E 1010 def +/uni045F 1011 def +/uni0460 1012 def +/uni0461 1013 def +/uni0462 1014 def +/uni0463 1015 def +/uni0464 1016 def +/uni0465 1017 def +/uni0466 1018 def +/uni0467 1019 def +/uni0468 1020 def +/uni0469 1021 def +/uni046A 1022 def +/uni046B 1023 def +/uni046C 1024 def +/uni046D 1025 def +/uni046E 1026 def +/uni046F 1027 def +/uni0470 1028 def +/uni0471 1029 def +/uni0472 1030 def +/uni0473 1031 def +/uni0474 1032 def +/uni0475 1033 def +/uni0476 1034 def +/uni0477 1035 def +/uni0478 1036 def +/uni0479 1037 def +/uni047A 1038 def +/uni047B 1039 def +/uni047C 1040 def +/uni047D 1041 def +/uni047E 1042 def +/uni047F 1043 def +/uni0480 1044 def +/uni0481 1045 def +/uni0482 1046 def +/uni0483 1047 def +/uni0484 1048 def +/uni0485 1049 def +/uni0486 1050 def +/uni0487 1051 def +/uni0488 1052 def +/uni0489 1053 def +/uni048A 1054 def +/uni048B 1055 def +/uni048C 1056 def +/uni048D 1057 def +/uni048E 1058 def +/uni048F 1059 def +/uni0490 1060 def +/uni0491 1061 def +/uni0492 1062 def +/uni0493 1063 def +/uni0494 1064 def +/uni0495 1065 def +/uni0496 1066 def +/uni0497 1067 def +/uni0498 1068 def +/uni0499 1069 def +/uni049A 1070 def +/uni049B 1071 def +/uni049C 1072 def +/uni049D 1073 def +/uni049E 1074 def +/uni049F 1075 def +/uni04A0 1076 def +/uni04A1 1077 def +/uni04A2 1078 def +/uni04A3 1079 def +/uni04A4 1080 def +/uni04A5 1081 def +/uni04A6 1082 def +/uni04A7 1083 def +/uni04A8 1084 def +/uni04A9 1085 def +/uni04AA 1086 def +/uni04AB 1087 def +/uni04AC 1088 def +/uni04AD 1089 def +/uni04AE 1090 def +/uni04AF 1091 def +/uni04B0 1092 def +/uni04B1 1093 def +/uni04B2 1094 def +/uni04B3 1095 def +/uni04B4 1096 def +/uni04B5 1097 def +/uni04B6 1098 def +/uni04B7 1099 def +/uni04B8 1100 def +/uni04B9 1101 def +/uni04BA 1102 def +/uni04BB 1103 def +/uni04BC 1104 def +/uni04BD 1105 def +/uni04BE 1106 def +/uni04BF 1107 def +/uni04C0 1108 def +/uni04C1 1109 def +/uni04C2 1110 def +/uni04C3 1111 def +/uni04C4 1112 def +/uni04C5 1113 def +/uni04C6 1114 def +/uni04C7 1115 def +/uni04C8 1116 def +/uni04C9 1117 def +/uni04CA 1118 def +/uni04CB 1119 def +/uni04CC 1120 def +/uni04CD 1121 def +/uni04CE 1122 def +/uni04CF 1123 def +/uni04D0 1124 def +/uni04D1 1125 def +/uni04D2 1126 def +/uni04D3 1127 def +/uni04D4 1128 def +/uni04D5 1129 def +/uni04D6 1130 def +/uni04D7 1131 def +/uni04D8 1132 def +/uni04D9 1133 def +/uni04DA 1134 def +/uni04DB 1135 def +/uni04DC 1136 def +/uni04DD 1137 def +/uni04DE 1138 def +/uni04DF 1139 def +/uni04E0 1140 def +/uni04E1 1141 def +/uni04E2 1142 def +/uni04E3 1143 def +/uni04E4 1144 def +/uni04E5 1145 def +/uni04E6 1146 def +/uni04E7 1147 def +/uni04E8 1148 def +/uni04E9 1149 def +/uni04EA 1150 def +/uni04EB 1151 def +/uni04EC 1152 def +/uni04ED 1153 def +/uni04EE 1154 def +/uni04EF 1155 def +/uni04F0 1156 def +/uni04F1 1157 def +/uni04F2 1158 def +/uni04F3 1159 def +/uni04F4 1160 def +/uni04F5 1161 def +/uni04F6 1162 def +/uni04F7 1163 def +/uni04F8 1164 def +/uni04F9 1165 def +/uni04FA 1166 def +/uni04FB 1167 def +/uni04FC 1168 def +/uni04FD 1169 def +/uni04FE 1170 def +/uni04FF 1171 def +/uni0500 1172 def +/uni0501 1173 def +/uni0502 1174 def +/uni0503 1175 def +/uni0504 1176 def +/uni0505 1177 def +/uni0506 1178 def +/uni0507 1179 def +/uni0508 1180 def +/uni0509 1181 def +/uni050A 1182 def +/uni050B 1183 def +/uni050C 1184 def +/uni050D 1185 def +/uni050E 1186 def +/uni050F 1187 def +/uni0510 1188 def +/uni0511 1189 def +/uni0512 1190 def +/uni0513 1191 def +/uni0514 1192 def +/uni0515 1193 def +/uni0516 1194 def +/uni0517 1195 def +/uni0518 1196 def +/uni0519 1197 def +/uni051A 1198 def +/uni051B 1199 def +/uni051C 1200 def +/uni051D 1201 def +/uni051E 1202 def +/uni051F 1203 def +/uni0520 1204 def +/uni0521 1205 def +/uni0522 1206 def +/uni0523 1207 def +/uni0524 1208 def +/uni0525 1209 def +/uni0531 1210 def +/uni0532 1211 def +/uni0533 1212 def +/uni0534 1213 def +/uni0535 1214 def +/uni0536 1215 def +/uni0537 1216 def +/uni0538 1217 def +/uni0539 1218 def +/uni053A 1219 def +/uni053B 1220 def +/uni053C 1221 def +/uni053D 1222 def +/uni053E 1223 def +/uni053F 1224 def +/uni0540 1225 def +/uni0541 1226 def +/uni0542 1227 def +/uni0543 1228 def +/uni0544 1229 def +/uni0545 1230 def +/uni0546 1231 def +/uni0547 1232 def +/uni0548 1233 def +/uni0549 1234 def +/uni054A 1235 def +/uni054B 1236 def +/uni054C 1237 def +/uni054D 1238 def +/uni054E 1239 def +/uni054F 1240 def +/uni0550 1241 def +/uni0551 1242 def +/uni0552 1243 def +/uni0553 1244 def +/uni0554 1245 def +/uni0555 1246 def +/uni0556 1247 def +/uni0559 1248 def +/uni055A 1249 def +/uni055B 1250 def +/uni055C 1251 def +/uni055D 1252 def +/uni055E 1253 def +/uni055F 1254 def +/uni0561 1255 def +/uni0562 1256 def +/uni0563 1257 def +/uni0564 1258 def +/uni0565 1259 def +/uni0566 1260 def +/uni0567 1261 def +/uni0568 1262 def +/uni0569 1263 def +/uni056A 1264 def +/uni056B 1265 def +/uni056C 1266 def +/uni056D 1267 def +/uni056E 1268 def +/uni056F 1269 def +/uni0570 1270 def +/uni0571 1271 def +/uni0572 1272 def +/uni0573 1273 def +/uni0574 1274 def +/uni0575 1275 def +/uni0576 1276 def +/uni0577 1277 def +/uni0578 1278 def +/uni0579 1279 def +/uni057A 1280 def +/uni057B 1281 def +/uni057C 1282 def +/uni057D 1283 def +/uni057E 1284 def +/uni057F 1285 def +/uni0580 1286 def +/uni0581 1287 def +/uni0582 1288 def +/uni0583 1289 def +/uni0584 1290 def +/uni0585 1291 def +/uni0586 1292 def +/uni0587 1293 def +/uni0589 1294 def +/uni058A 1295 def +/uni05B0 1296 def +/uni05B1 1297 def +/uni05B2 1298 def +/uni05B3 1299 def +/uni05B4 1300 def +/uni05B5 1301 def +/uni05B6 1302 def +/uni05B7 1303 def +/uni05B8 1304 def +/uni05B9 1305 def +/uni05BA 1306 def +/uni05BB 1307 def +/uni05BC 1308 def +/uni05BD 1309 def +/uni05BE 1310 def +/uni05BF 1311 def +/uni05C0 1312 def +/uni05C1 1313 def +/uni05C2 1314 def +/uni05C3 1315 def +/uni05C6 1316 def +/uni05C7 1317 def +/uni05D0 1318 def +/uni05D1 1319 def +/uni05D2 1320 def +/uni05D3 1321 def +/uni05D4 1322 def +/uni05D5 1323 def +/uni05D6 1324 def +/uni05D7 1325 def +/uni05D8 1326 def +/uni05D9 1327 def +/uni05DA 1328 def +/uni05DB 1329 def +/uni05DC 1330 def +/uni05DD 1331 def +/uni05DE 1332 def +/uni05DF 1333 def +/uni05E0 1334 def +/uni05E1 1335 def +/uni05E2 1336 def +/uni05E3 1337 def +/uni05E4 1338 def +/uni05E5 1339 def +/uni05E6 1340 def +/uni05E7 1341 def +/uni05E8 1342 def +/uni05E9 1343 def +/uni05EA 1344 def +/uni05F0 1345 def +/uni05F1 1346 def +/uni05F2 1347 def +/uni05F3 1348 def +/uni05F4 1349 def +/uni0606 1350 def +/uni0607 1351 def +/uni0609 1352 def +/uni060A 1353 def +/uni060C 1354 def +/uni0615 1355 def +/uni061B 1356 def +/uni061F 1357 def +/uni0621 1358 def +/uni0622 1359 def +/uni0623 1360 def +/uni0624 1361 def +/uni0625 1362 def +/uni0626 1363 def +/uni0627 1364 def +/uni0628 1365 def +/uni0629 1366 def +/uni062A 1367 def +/uni062B 1368 def +/uni062C 1369 def +/uni062D 1370 def +/uni062E 1371 def +/uni062F 1372 def +/uni0630 1373 def +/uni0631 1374 def +/uni0632 1375 def +/uni0633 1376 def +/uni0634 1377 def +/uni0635 1378 def +/uni0636 1379 def +/uni0637 1380 def +/uni0638 1381 def +/uni0639 1382 def +/uni063A 1383 def +/uni0640 1384 def +/uni0641 1385 def +/uni0642 1386 def +/uni0643 1387 def +/uni0644 1388 def +/uni0645 1389 def +/uni0646 1390 def +/uni0647 1391 def +/uni0648 1392 def +/uni0649 1393 def +/uni064A 1394 def +/uni064B 1395 def +/uni064C 1396 def +/uni064D 1397 def +/uni064E 1398 def +/uni064F 1399 def +/uni0650 1400 def +/uni0651 1401 def +/uni0652 1402 def +/uni0653 1403 def +/uni0654 1404 def +/uni0655 1405 def +/uni0657 1406 def +/uni065A 1407 def +/uni0660 1408 def +/uni0661 1409 def +/uni0662 1410 def +/uni0663 1411 def +/uni0664 1412 def +/uni0665 1413 def +/uni0666 1414 def +/uni0667 1415 def +/uni0668 1416 def +/uni0669 1417 def +/uni066A 1418 def +/uni066B 1419 def +/uni066C 1420 def +/uni066D 1421 def +/uni066E 1422 def +/uni066F 1423 def +/uni0670 1424 def +/uni0674 1425 def +/uni0679 1426 def +/uni067A 1427 def +/uni067B 1428 def +/uni067C 1429 def +/uni067D 1430 def +/uni067E 1431 def +/uni067F 1432 def +/uni0680 1433 def +/uni0681 1434 def +/uni0682 1435 def +/uni0683 1436 def +/uni0684 1437 def +/uni0685 1438 def +/uni0686 1439 def +/uni0687 1440 def +/uni0688 1441 def +/uni0689 1442 def +/uni068A 1443 def +/uni068B 1444 def +/uni068C 1445 def +/uni068D 1446 def +/uni068E 1447 def +/uni068F 1448 def +/uni0690 1449 def +/uni0691 1450 def +/uni0692 1451 def +/uni0693 1452 def +/uni0694 1453 def +/uni0695 1454 def +/uni0696 1455 def +/uni0697 1456 def +/uni0698 1457 def +/uni0699 1458 def +/uni069A 1459 def +/uni069B 1460 def +/uni069C 1461 def +/uni069D 1462 def +/uni069E 1463 def +/uni069F 1464 def +/uni06A0 1465 def +/uni06A1 1466 def +/uni06A2 1467 def +/uni06A3 1468 def +/uni06A4 1469 def +/uni06A5 1470 def +/uni06A6 1471 def +/uni06A7 1472 def +/uni06A8 1473 def +/uni06A9 1474 def +/uni06AA 1475 def +/uni06AB 1476 def +/uni06AC 1477 def +/uni06AD 1478 def +/uni06AE 1479 def +/uni06AF 1480 def +/uni06B0 1481 def +/uni06B1 1482 def +/uni06B2 1483 def +/uni06B3 1484 def +/uni06B4 1485 def +/uni06B5 1486 def +/uni06B6 1487 def +/uni06B7 1488 def +/uni06B8 1489 def +/uni06B9 1490 def +/uni06BA 1491 def +/uni06BB 1492 def +/uni06BC 1493 def +/uni06BD 1494 def +/uni06BE 1495 def +/uni06BF 1496 def +/uni06C6 1497 def +/uni06C7 1498 def +/uni06C8 1499 def +/uni06CB 1500 def +/uni06CC 1501 def +/uni06CE 1502 def +/uni06D0 1503 def +/uni06D5 1504 def +/uni06F0 1505 def +/uni06F1 1506 def +/uni06F2 1507 def +/uni06F3 1508 def +/uni06F4 1509 def +/uni06F5 1510 def +/uni06F6 1511 def +/uni06F7 1512 def +/uni06F8 1513 def +/uni06F9 1514 def +/uni07C0 1515 def +/uni07C1 1516 def +/uni07C2 1517 def +/uni07C3 1518 def +/uni07C4 1519 def +/uni07C5 1520 def +/uni07C6 1521 def +/uni07C7 1522 def +/uni07C8 1523 def +/uni07C9 1524 def +/uni07CA 1525 def +/uni07CB 1526 def +/uni07CC 1527 def +/uni07CD 1528 def +/uni07CE 1529 def +/uni07CF 1530 def +/uni07D0 1531 def +/uni07D1 1532 def +/uni07D2 1533 def +/uni07D3 1534 def +/uni07D4 1535 def +/uni07D5 1536 def +/uni07D6 1537 def +/uni07D7 1538 def +/uni07D8 1539 def +/uni07D9 1540 def +/uni07DA 1541 def +/uni07DB 1542 def +/uni07DC 1543 def +/uni07DD 1544 def +/uni07DE 1545 def +/uni07DF 1546 def +/uni07E0 1547 def +/uni07E1 1548 def +/uni07E2 1549 def +/uni07E3 1550 def +/uni07E4 1551 def +/uni07E5 1552 def +/uni07E6 1553 def +/uni07E7 1554 def +/uni07EB 1555 def +/uni07EC 1556 def +/uni07ED 1557 def +/uni07EE 1558 def +/uni07EF 1559 def +/uni07F0 1560 def +/uni07F1 1561 def +/uni07F2 1562 def +/uni07F3 1563 def +/uni07F4 1564 def +/uni07F5 1565 def +/uni07F8 1566 def +/uni07F9 1567 def +/uni07FA 1568 def +/uni0E3F 1569 def +/uni0E81 1570 def +/uni0E82 1571 def +/uni0E84 1572 def +/uni0E87 1573 def +/uni0E88 1574 def +/uni0E8A 1575 def +/uni0E8D 1576 def +/uni0E94 1577 def +/uni0E95 1578 def +/uni0E96 1579 def +/uni0E97 1580 def +/uni0E99 1581 def +/uni0E9A 1582 def +/uni0E9B 1583 def +/uni0E9C 1584 def +/uni0E9D 1585 def +/uni0E9E 1586 def +/uni0E9F 1587 def +/uni0EA1 1588 def +/uni0EA2 1589 def +/uni0EA3 1590 def +/uni0EA5 1591 def +/uni0EA7 1592 def +/uni0EAA 1593 def +/uni0EAB 1594 def +/uni0EAD 1595 def +/uni0EAE 1596 def +/uni0EAF 1597 def +/uni0EB0 1598 def +/uni0EB1 1599 def +/uni0EB2 1600 def +/uni0EB3 1601 def +/uni0EB4 1602 def +/uni0EB5 1603 def +/uni0EB6 1604 def +/uni0EB7 1605 def +/uni0EB8 1606 def +/uni0EB9 1607 def +/uni0EBB 1608 def +/uni0EBC 1609 def +/uni0EBD 1610 def +/uni0EC0 1611 def +/uni0EC1 1612 def +/uni0EC2 1613 def +/uni0EC3 1614 def +/uni0EC4 1615 def +/uni0EC6 1616 def +/uni0EC8 1617 def +/uni0EC9 1618 def +/uni0ECA 1619 def +/uni0ECB 1620 def +/uni0ECC 1621 def +/uni0ECD 1622 def +/uni0ED0 1623 def +/uni0ED1 1624 def +/uni0ED2 1625 def +/uni0ED3 1626 def +/uni0ED4 1627 def +/uni0ED5 1628 def +/uni0ED6 1629 def +/uni0ED7 1630 def +/uni0ED8 1631 def +/uni0ED9 1632 def +/uni0EDC 1633 def +/uni0EDD 1634 def +/uni10A0 1635 def +/uni10A1 1636 def +/uni10A2 1637 def +/uni10A3 1638 def +/uni10A4 1639 def +/uni10A5 1640 def +/uni10A6 1641 def +/uni10A7 1642 def +/uni10A8 1643 def +/uni10A9 1644 def +/uni10AA 1645 def +/uni10AB 1646 def +/uni10AC 1647 def +/uni10AD 1648 def +/uni10AE 1649 def +/uni10AF 1650 def +/uni10B0 1651 def +/uni10B1 1652 def +/uni10B2 1653 def +/uni10B3 1654 def +/uni10B4 1655 def +/uni10B5 1656 def +/uni10B6 1657 def +/uni10B7 1658 def +/uni10B8 1659 def +/uni10B9 1660 def +/uni10BA 1661 def +/uni10BB 1662 def +/uni10BC 1663 def +/uni10BD 1664 def +/uni10BE 1665 def +/uni10BF 1666 def +/uni10C0 1667 def +/uni10C1 1668 def +/uni10C2 1669 def +/uni10C3 1670 def +/uni10C4 1671 def +/uni10C5 1672 def +/uni10D0 1673 def +/uni10D1 1674 def +/uni10D2 1675 def +/uni10D3 1676 def +/uni10D4 1677 def +/uni10D5 1678 def +/uni10D6 1679 def +/uni10D7 1680 def +/uni10D8 1681 def +/uni10D9 1682 def +/uni10DA 1683 def +/uni10DB 1684 def +/uni10DC 1685 def +/uni10DD 1686 def +/uni10DE 1687 def +/uni10DF 1688 def +/uni10E0 1689 def +/uni10E1 1690 def +/uni10E2 1691 def +/uni10E3 1692 def +/uni10E4 1693 def +/uni10E5 1694 def +/uni10E6 1695 def +/uni10E7 1696 def +/uni10E8 1697 def +/uni10E9 1698 def +/uni10EA 1699 def +/uni10EB 1700 def +/uni10EC 1701 def +/uni10ED 1702 def +/uni10EE 1703 def +/uni10EF 1704 def +/uni10F0 1705 def +/uni10F1 1706 def +/uni10F2 1707 def +/uni10F3 1708 def +/uni10F4 1709 def +/uni10F5 1710 def +/uni10F6 1711 def +/uni10F7 1712 def +/uni10F8 1713 def +/uni10F9 1714 def +/uni10FA 1715 def +/uni10FB 1716 def +/uni10FC 1717 def +/uni1401 1718 def +/uni1402 1719 def +/uni1403 1720 def +/uni1404 1721 def +/uni1405 1722 def +/uni1406 1723 def +/uni1407 1724 def +/uni1409 1725 def +/uni140A 1726 def +/uni140B 1727 def +/uni140C 1728 def +/uni140D 1729 def +/uni140E 1730 def +/uni140F 1731 def +/uni1410 1732 def +/uni1411 1733 def +/uni1412 1734 def +/uni1413 1735 def +/uni1414 1736 def +/uni1415 1737 def +/uni1416 1738 def +/uni1417 1739 def +/uni1418 1740 def +/uni1419 1741 def +/uni141A 1742 def +/uni141B 1743 def +/uni141D 1744 def +/uni141E 1745 def +/uni141F 1746 def +/uni1420 1747 def +/uni1421 1748 def +/uni1422 1749 def +/uni1423 1750 def +/uni1424 1751 def +/uni1425 1752 def +/uni1426 1753 def +/uni1427 1754 def +/uni1428 1755 def +/uni1429 1756 def +/uni142A 1757 def +/uni142B 1758 def +/uni142C 1759 def +/uni142D 1760 def +/uni142E 1761 def +/uni142F 1762 def +/uni1430 1763 def +/uni1431 1764 def +/uni1432 1765 def +/uni1433 1766 def +/uni1434 1767 def +/uni1435 1768 def +/uni1437 1769 def +/uni1438 1770 def +/uni1439 1771 def +/uni143A 1772 def +/uni143B 1773 def +/uni143C 1774 def +/uni143D 1775 def +/uni143E 1776 def +/uni143F 1777 def +/uni1440 1778 def +/uni1441 1779 def +/uni1442 1780 def +/uni1443 1781 def +/uni1444 1782 def +/uni1445 1783 def +/uni1446 1784 def +/uni1447 1785 def +/uni1448 1786 def +/uni1449 1787 def +/uni144A 1788 def +/uni144C 1789 def +/uni144D 1790 def +/uni144E 1791 def +/uni144F 1792 def +/uni1450 1793 def +/uni1451 1794 def +/uni1452 1795 def +/uni1454 1796 def +/uni1455 1797 def +/uni1456 1798 def +/uni1457 1799 def +/uni1458 1800 def +/uni1459 1801 def +/uni145A 1802 def +/uni145B 1803 def +/uni145C 1804 def +/uni145D 1805 def +/uni145E 1806 def +/uni145F 1807 def +/uni1460 1808 def +/uni1461 1809 def +/uni1462 1810 def +/uni1463 1811 def +/uni1464 1812 def +/uni1465 1813 def +/uni1466 1814 def +/uni1467 1815 def +/uni1468 1816 def +/uni1469 1817 def +/uni146A 1818 def +/uni146B 1819 def +/uni146C 1820 def +/uni146D 1821 def +/uni146E 1822 def +/uni146F 1823 def +/uni1470 1824 def +/uni1471 1825 def +/uni1472 1826 def +/uni1473 1827 def +/uni1474 1828 def +/uni1475 1829 def +/uni1476 1830 def +/uni1477 1831 def +/uni1478 1832 def +/uni1479 1833 def +/uni147A 1834 def +/uni147B 1835 def +/uni147C 1836 def +/uni147D 1837 def +/uni147E 1838 def +/uni147F 1839 def +/uni1480 1840 def +/uni1481 1841 def +/uni1482 1842 def +/uni1483 1843 def +/uni1484 1844 def +/uni1485 1845 def +/uni1486 1846 def +/uni1487 1847 def +/uni1488 1848 def +/uni1489 1849 def +/uni148A 1850 def +/uni148B 1851 def +/uni148C 1852 def +/uni148D 1853 def +/uni148E 1854 def +/uni148F 1855 def +/uni1490 1856 def +/uni1491 1857 def +/uni1492 1858 def +/uni1493 1859 def +/uni1494 1860 def +/uni1495 1861 def +/uni1496 1862 def +/uni1497 1863 def +/uni1498 1864 def +/uni1499 1865 def +/uni149A 1866 def +/uni149B 1867 def +/uni149C 1868 def +/uni149D 1869 def +/uni149E 1870 def +/uni149F 1871 def +/uni14A0 1872 def +/uni14A1 1873 def +/uni14A2 1874 def +/uni14A3 1875 def +/uni14A4 1876 def +/uni14A5 1877 def +/uni14A6 1878 def +/uni14A7 1879 def +/uni14A8 1880 def +/uni14A9 1881 def +/uni14AA 1882 def +/uni14AB 1883 def +/uni14AC 1884 def +/uni14AD 1885 def +/uni14AE 1886 def +/uni14AF 1887 def +/uni14B0 1888 def +/uni14B1 1889 def +/uni14B2 1890 def +/uni14B3 1891 def +/uni14B4 1892 def +/uni14B5 1893 def +/uni14B6 1894 def +/uni14B7 1895 def +/uni14B8 1896 def +/uni14B9 1897 def +/uni14BA 1898 def +/uni14BB 1899 def +/uni14BC 1900 def +/uni14BD 1901 def +/uni14C0 1902 def +/uni14C1 1903 def +/uni14C2 1904 def +/uni14C3 1905 def +/uni14C4 1906 def +/uni14C5 1907 def +/uni14C6 1908 def +/uni14C7 1909 def +/uni14C8 1910 def +/uni14C9 1911 def +/uni14CA 1912 def +/uni14CB 1913 def +/uni14CC 1914 def +/uni14CD 1915 def +/uni14CE 1916 def +/uni14CF 1917 def +/uni14D0 1918 def +/uni14D1 1919 def +/uni14D2 1920 def +/uni14D3 1921 def +/uni14D4 1922 def +/uni14D5 1923 def +/uni14D6 1924 def +/uni14D7 1925 def +/uni14D8 1926 def +/uni14D9 1927 def +/uni14DA 1928 def +/uni14DB 1929 def +/uni14DC 1930 def +/uni14DD 1931 def +/uni14DE 1932 def +/uni14DF 1933 def +/uni14E0 1934 def +/uni14E1 1935 def +/uni14E2 1936 def +/uni14E3 1937 def +/uni14E4 1938 def +/uni14E5 1939 def +/uni14E6 1940 def +/uni14E7 1941 def +/uni14E8 1942 def +/uni14E9 1943 def +/uni14EA 1944 def +/uni14EC 1945 def +/uni14ED 1946 def +/uni14EE 1947 def +/uni14EF 1948 def +/uni14F0 1949 def +/uni14F1 1950 def +/uni14F2 1951 def +/uni14F3 1952 def +/uni14F4 1953 def +/uni14F5 1954 def +/uni14F6 1955 def +/uni14F7 1956 def +/uni14F8 1957 def +/uni14F9 1958 def +/uni14FA 1959 def +/uni14FB 1960 def +/uni14FC 1961 def +/uni14FD 1962 def +/uni14FE 1963 def +/uni14FF 1964 def +/uni1500 1965 def +/uni1501 1966 def +/uni1502 1967 def +/uni1503 1968 def +/uni1504 1969 def +/uni1505 1970 def +/uni1506 1971 def +/uni1507 1972 def +/uni1510 1973 def +/uni1511 1974 def +/uni1512 1975 def +/uni1513 1976 def +/uni1514 1977 def +/uni1515 1978 def +/uni1516 1979 def +/uni1517 1980 def +/uni1518 1981 def +/uni1519 1982 def +/uni151A 1983 def +/uni151B 1984 def +/uni151C 1985 def +/uni151D 1986 def +/uni151E 1987 def +/uni151F 1988 def +/uni1520 1989 def +/uni1521 1990 def +/uni1522 1991 def +/uni1523 1992 def +/uni1524 1993 def +/uni1525 1994 def +/uni1526 1995 def +/uni1527 1996 def +/uni1528 1997 def +/uni1529 1998 def +/uni152A 1999 def +/uni152B 2000 def +/uni152C 2001 def +/uni152D 2002 def +/uni152E 2003 def +/uni152F 2004 def +/uni1530 2005 def +/uni1531 2006 def +/uni1532 2007 def +/uni1533 2008 def +/uni1534 2009 def +/uni1535 2010 def +/uni1536 2011 def +/uni1537 2012 def +/uni1538 2013 def +/uni1539 2014 def +/uni153A 2015 def +/uni153B 2016 def +/uni153C 2017 def +/uni153D 2018 def +/uni153E 2019 def +/uni1540 2020 def +/uni1541 2021 def +/uni1542 2022 def +/uni1543 2023 def +/uni1544 2024 def +/uni1545 2025 def +/uni1546 2026 def +/uni1547 2027 def +/uni1548 2028 def +/uni1549 2029 def +/uni154A 2030 def +/uni154B 2031 def +/uni154C 2032 def +/uni154D 2033 def +/uni154E 2034 def +/uni154F 2035 def +/uni1550 2036 def +/uni1552 2037 def +/uni1553 2038 def +/uni1554 2039 def +/uni1555 2040 def +/uni1556 2041 def +/uni1557 2042 def +/uni1558 2043 def +/uni1559 2044 def +/uni155A 2045 def +/uni155B 2046 def +/uni155C 2047 def +/uni155D 2048 def +/uni155E 2049 def +/uni155F 2050 def +/uni1560 2051 def +/uni1561 2052 def +/uni1562 2053 def +/uni1563 2054 def +/uni1564 2055 def +/uni1565 2056 def +/uni1566 2057 def +/uni1567 2058 def +/uni1568 2059 def +/uni1569 2060 def +/uni156A 2061 def +/uni1574 2062 def +/uni1575 2063 def +/uni1576 2064 def +/uni1577 2065 def +/uni1578 2066 def +/uni1579 2067 def +/uni157A 2068 def +/uni157B 2069 def +/uni157C 2070 def +/uni157D 2071 def +/uni157E 2072 def +/uni157F 2073 def +/uni1580 2074 def +/uni1581 2075 def +/uni1582 2076 def +/uni1583 2077 def +/uni1584 2078 def +/uni1585 2079 def +/uni158A 2080 def +/uni158B 2081 def +/uni158C 2082 def +/uni158D 2083 def +/uni158E 2084 def +/uni158F 2085 def +/uni1590 2086 def +/uni1591 2087 def +/uni1592 2088 def +/uni1593 2089 def +/uni1594 2090 def +/uni1595 2091 def +/uni1596 2092 def +/uni15A0 2093 def +/uni15A1 2094 def +/uni15A2 2095 def +/uni15A3 2096 def +/uni15A4 2097 def +/uni15A5 2098 def +/uni15A6 2099 def +/uni15A7 2100 def +/uni15A8 2101 def +/uni15A9 2102 def +/uni15AA 2103 def +/uni15AB 2104 def +/uni15AC 2105 def +/uni15AD 2106 def +/uni15AE 2107 def +/uni15AF 2108 def +/uni15DE 2109 def +/uni15E1 2110 def +/uni1646 2111 def +/uni1647 2112 def +/uni166E 2113 def +/uni166F 2114 def +/uni1670 2115 def +/uni1671 2116 def +/uni1672 2117 def +/uni1673 2118 def +/uni1674 2119 def +/uni1675 2120 def +/uni1676 2121 def +/uni1680 2122 def +/uni1681 2123 def +/uni1682 2124 def +/uni1683 2125 def +/uni1684 2126 def +/uni1685 2127 def +/uni1686 2128 def +/uni1687 2129 def +/uni1688 2130 def +/uni1689 2131 def +/uni168A 2132 def +/uni168B 2133 def +/uni168C 2134 def +/uni168D 2135 def +/uni168E 2136 def +/uni168F 2137 def +/uni1690 2138 def +/uni1691 2139 def +/uni1692 2140 def +/uni1693 2141 def +/uni1694 2142 def +/uni1695 2143 def +/uni1696 2144 def +/uni1697 2145 def +/uni1698 2146 def +/uni1699 2147 def +/uni169A 2148 def +/uni169B 2149 def +/uni169C 2150 def +/uni1D00 2151 def +/uni1D01 2152 def +/uni1D02 2153 def +/uni1D03 2154 def +/uni1D04 2155 def +/uni1D05 2156 def +/uni1D06 2157 def +/uni1D07 2158 def +/uni1D08 2159 def +/uni1D09 2160 def +/uni1D0A 2161 def +/uni1D0B 2162 def +/uni1D0C 2163 def +/uni1D0D 2164 def +/uni1D0E 2165 def +/uni1D0F 2166 def +/uni1D10 2167 def +/uni1D11 2168 def +/uni1D12 2169 def +/uni1D13 2170 def +/uni1D14 2171 def +/uni1D16 2172 def +/uni1D17 2173 def +/uni1D18 2174 def +/uni1D19 2175 def +/uni1D1A 2176 def +/uni1D1B 2177 def +/uni1D1C 2178 def +/uni1D1D 2179 def +/uni1D1E 2180 def +/uni1D1F 2181 def +/uni1D20 2182 def +/uni1D21 2183 def +/uni1D22 2184 def +/uni1D23 2185 def +/uni1D26 2186 def +/uni1D27 2187 def +/uni1D28 2188 def +/uni1D29 2189 def +/uni1D2A 2190 def +/uni1D2B 2191 def +/uni1D2C 2192 def +/uni1D2D 2193 def +/uni1D2E 2194 def +/uni1D30 2195 def +/uni1D31 2196 def +/uni1D32 2197 def +/uni1D33 2198 def +/uni1D34 2199 def +/uni1D35 2200 def +/uni1D36 2201 def +/uni1D37 2202 def +/uni1D38 2203 def +/uni1D39 2204 def +/uni1D3A 2205 def +/uni1D3B 2206 def +/uni1D3C 2207 def +/uni1D3D 2208 def +/uni1D3E 2209 def +/uni1D3F 2210 def +/uni1D40 2211 def +/uni1D41 2212 def +/uni1D42 2213 def +/uni1D43 2214 def +/uni1D44 2215 def +/uni1D45 2216 def +/uni1D46 2217 def +/uni1D47 2218 def +/uni1D48 2219 def +/uni1D49 2220 def +/uni1D4A 2221 def +/uni1D4B 2222 def +/uni1D4C 2223 def +/uni1D4D 2224 def +/uni1D4E 2225 def +/uni1D4F 2226 def +/uni1D50 2227 def +/uni1D51 2228 def +/uni1D52 2229 def +/uni1D53 2230 def +/uni1D54 2231 def +/uni1D55 2232 def +/uni1D56 2233 def +/uni1D57 2234 def +/uni1D58 2235 def +/uni1D59 2236 def +/uni1D5A 2237 def +/uni1D5B 2238 def +/uni1D5D 2239 def +/uni1D5E 2240 def +/uni1D5F 2241 def +/uni1D60 2242 def +/uni1D61 2243 def +/uni1D62 2244 def +/uni1D63 2245 def +/uni1D64 2246 def +/uni1D65 2247 def +/uni1D66 2248 def +/uni1D67 2249 def +/uni1D68 2250 def +/uni1D69 2251 def +/uni1D6A 2252 def +/uni1D77 2253 def +/uni1D78 2254 def +/uni1D7B 2255 def +/uni1D7D 2256 def +/uni1D85 2257 def +/uni1D9B 2258 def +/uni1D9C 2259 def +/uni1D9D 2260 def +/uni1D9E 2261 def +/uni1D9F 2262 def +/uni1DA0 2263 def +/uni1DA1 2264 def +/uni1DA2 2265 def +/uni1DA3 2266 def +/uni1DA4 2267 def +/uni1DA5 2268 def +/uni1DA6 2269 def +/uni1DA7 2270 def +/uni1DA8 2271 def +/uni1DA9 2272 def +/uni1DAA 2273 def +/uni1DAB 2274 def +/uni1DAC 2275 def +/uni1DAD 2276 def +/uni1DAE 2277 def +/uni1DAF 2278 def +/uni1DB0 2279 def +/uni1DB1 2280 def +/uni1DB2 2281 def +/uni1DB3 2282 def +/uni1DB4 2283 def +/uni1DB5 2284 def +/uni1DB6 2285 def +/uni1DB7 2286 def +/uni1DB8 2287 def +/uni1DB9 2288 def +/uni1DBA 2289 def +/uni1DBB 2290 def +/uni1DBC 2291 def +/uni1DBD 2292 def +/uni1DBE 2293 def +/uni1DBF 2294 def +/uni1DC4 2295 def +/uni1DC5 2296 def +/uni1DC6 2297 def +/uni1DC7 2298 def +/uni1DC8 2299 def +/uni1DC9 2300 def +/uni1E00 2301 def +/uni1E01 2302 def +/uni1E02 2303 def +/uni1E03 2304 def +/uni1E04 2305 def +/uni1E05 2306 def +/uni1E06 2307 def +/uni1E07 2308 def +/uni1E08 2309 def +/uni1E09 2310 def +/uni1E0A 2311 def +/uni1E0B 2312 def +/uni1E0C 2313 def +/uni1E0D 2314 def +/uni1E0E 2315 def +/uni1E0F 2316 def +/uni1E10 2317 def +/uni1E11 2318 def +/uni1E12 2319 def +/uni1E13 2320 def +/uni1E14 2321 def +/uni1E15 2322 def +/uni1E16 2323 def +/uni1E17 2324 def +/uni1E18 2325 def +/uni1E19 2326 def +/uni1E1A 2327 def +/uni1E1B 2328 def +/uni1E1C 2329 def +/uni1E1D 2330 def +/uni1E1E 2331 def +/uni1E1F 2332 def +/uni1E20 2333 def +/uni1E21 2334 def +/uni1E22 2335 def +/uni1E23 2336 def +/uni1E24 2337 def +/uni1E25 2338 def +/uni1E26 2339 def +/uni1E27 2340 def +/uni1E28 2341 def +/uni1E29 2342 def +/uni1E2A 2343 def +/uni1E2B 2344 def +/uni1E2C 2345 def +/uni1E2D 2346 def +/uni1E2E 2347 def +/uni1E2F 2348 def +/uni1E30 2349 def +/uni1E31 2350 def +/uni1E32 2351 def +/uni1E33 2352 def +/uni1E34 2353 def +/uni1E35 2354 def +/uni1E36 2355 def +/uni1E37 2356 def +/uni1E38 2357 def +/uni1E39 2358 def +/uni1E3A 2359 def +/uni1E3B 2360 def +/uni1E3C 2361 def +/uni1E3D 2362 def +/uni1E3E 2363 def +/uni1E3F 2364 def +/uni1E40 2365 def +/uni1E41 2366 def +/uni1E42 2367 def +/uni1E43 2368 def +/uni1E44 2369 def +/uni1E45 2370 def +/uni1E46 2371 def +/uni1E47 2372 def +/uni1E48 2373 def +/uni1E49 2374 def +/uni1E4A 2375 def +/uni1E4B 2376 def +/uni1E4C 2377 def +/uni1E4D 2378 def +/uni1E4E 2379 def +/uni1E4F 2380 def +/uni1E50 2381 def +/uni1E51 2382 def +/uni1E52 2383 def +/uni1E53 2384 def +/uni1E54 2385 def +/uni1E55 2386 def +/uni1E56 2387 def +/uni1E57 2388 def +/uni1E58 2389 def +/uni1E59 2390 def +/uni1E5A 2391 def +/uni1E5B 2392 def +/uni1E5C 2393 def +/uni1E5D 2394 def +/uni1E5E 2395 def +/uni1E5F 2396 def +/uni1E60 2397 def +/uni1E61 2398 def +/uni1E62 2399 def +/uni1E63 2400 def +/uni1E64 2401 def +/uni1E65 2402 def +/uni1E66 2403 def +/uni1E67 2404 def +/uni1E68 2405 def +/uni1E69 2406 def +/uni1E6A 2407 def +/uni1E6B 2408 def +/uni1E6C 2409 def +/uni1E6D 2410 def +/uni1E6E 2411 def +/uni1E6F 2412 def +/uni1E70 2413 def +/uni1E71 2414 def +/uni1E72 2415 def +/uni1E73 2416 def +/uni1E74 2417 def +/uni1E75 2418 def +/uni1E76 2419 def +/uni1E77 2420 def +/uni1E78 2421 def +/uni1E79 2422 def +/uni1E7A 2423 def +/uni1E7B 2424 def +/uni1E7C 2425 def +/uni1E7D 2426 def +/uni1E7E 2427 def +/uni1E7F 2428 def +/Wgrave 2429 def +/wgrave 2430 def +/Wacute 2431 def +/wacute 2432 def +/Wdieresis 2433 def +/wdieresis 2434 def +/uni1E86 2435 def +/uni1E87 2436 def +/uni1E88 2437 def +/uni1E89 2438 def +/uni1E8A 2439 def +/uni1E8B 2440 def +/uni1E8C 2441 def +/uni1E8D 2442 def +/uni1E8E 2443 def +/uni1E8F 2444 def +/uni1E90 2445 def +/uni1E91 2446 def +/uni1E92 2447 def +/uni1E93 2448 def +/uni1E94 2449 def +/uni1E95 2450 def +/uni1E96 2451 def +/uni1E97 2452 def +/uni1E98 2453 def +/uni1E99 2454 def +/uni1E9A 2455 def +/uni1E9B 2456 def +/uni1E9C 2457 def +/uni1E9D 2458 def +/uni1E9E 2459 def +/uni1E9F 2460 def +/uni1EA0 2461 def +/uni1EA1 2462 def +/uni1EA2 2463 def +/uni1EA3 2464 def +/uni1EA4 2465 def +/uni1EA5 2466 def +/uni1EA6 2467 def +/uni1EA7 2468 def +/uni1EA8 2469 def +/uni1EA9 2470 def +/uni1EAA 2471 def +/uni1EAB 2472 def +/uni1EAC 2473 def +/uni1EAD 2474 def +/uni1EAE 2475 def +/uni1EAF 2476 def +/uni1EB0 2477 def +/uni1EB1 2478 def +/uni1EB2 2479 def +/uni1EB3 2480 def +/uni1EB4 2481 def +/uni1EB5 2482 def +/uni1EB6 2483 def +/uni1EB7 2484 def +/uni1EB8 2485 def +/uni1EB9 2486 def +/uni1EBA 2487 def +/uni1EBB 2488 def +/uni1EBC 2489 def +/uni1EBD 2490 def +/uni1EBE 2491 def +/uni1EBF 2492 def +/uni1EC0 2493 def +/uni1EC1 2494 def +/uni1EC2 2495 def +/uni1EC3 2496 def +/uni1EC4 2497 def +/uni1EC5 2498 def +/uni1EC6 2499 def +/uni1EC7 2500 def +/uni1EC8 2501 def +/uni1EC9 2502 def +/uni1ECA 2503 def +/uni1ECB 2504 def +/uni1ECC 2505 def +/uni1ECD 2506 def +/uni1ECE 2507 def +/uni1ECF 2508 def +/uni1ED0 2509 def +/uni1ED1 2510 def +/uni1ED2 2511 def +/uni1ED3 2512 def +/uni1ED4 2513 def +/uni1ED5 2514 def +/uni1ED6 2515 def +/uni1ED7 2516 def +/uni1ED8 2517 def +/uni1ED9 2518 def +/uni1EDA 2519 def +/uni1EDB 2520 def +/uni1EDC 2521 def +/uni1EDD 2522 def +/uni1EDE 2523 def +/uni1EDF 2524 def +/uni1EE0 2525 def +/uni1EE1 2526 def +/uni1EE2 2527 def +/uni1EE3 2528 def +/uni1EE4 2529 def +/uni1EE5 2530 def +/uni1EE6 2531 def +/uni1EE7 2532 def +/uni1EE8 2533 def +/uni1EE9 2534 def +/uni1EEA 2535 def +/uni1EEB 2536 def +/uni1EEC 2537 def +/uni1EED 2538 def +/uni1EEE 2539 def +/uni1EEF 2540 def +/uni1EF0 2541 def +/uni1EF1 2542 def +/Ygrave 2543 def +/ygrave 2544 def +/uni1EF4 2545 def +/uni1EF5 2546 def +/uni1EF6 2547 def +/uni1EF7 2548 def +/uni1EF8 2549 def +/uni1EF9 2550 def +/uni1EFA 2551 def +/uni1EFB 2552 def +/uni1F00 2553 def +/uni1F01 2554 def +/uni1F02 2555 def +/uni1F03 2556 def +/uni1F04 2557 def +/uni1F05 2558 def +/uni1F06 2559 def +/uni1F07 2560 def +/uni1F08 2561 def +/uni1F09 2562 def +/uni1F0A 2563 def +/uni1F0B 2564 def +/uni1F0C 2565 def +/uni1F0D 2566 def +/uni1F0E 2567 def +/uni1F0F 2568 def +/uni1F10 2569 def +/uni1F11 2570 def +/uni1F12 2571 def +/uni1F13 2572 def +/uni1F14 2573 def +/uni1F15 2574 def +/uni1F18 2575 def +/uni1F19 2576 def +/uni1F1A 2577 def +/uni1F1B 2578 def +/uni1F1C 2579 def +/uni1F1D 2580 def +/uni1F20 2581 def +/uni1F21 2582 def +/uni1F22 2583 def +/uni1F23 2584 def +/uni1F24 2585 def +/uni1F25 2586 def +/uni1F26 2587 def +/uni1F27 2588 def +/uni1F28 2589 def +/uni1F29 2590 def +/uni1F2A 2591 def +/uni1F2B 2592 def +/uni1F2C 2593 def +/uni1F2D 2594 def +/uni1F2E 2595 def +/uni1F2F 2596 def +/uni1F30 2597 def +/uni1F31 2598 def +/uni1F32 2599 def +/uni1F33 2600 def +/uni1F34 2601 def +/uni1F35 2602 def +/uni1F36 2603 def +/uni1F37 2604 def +/uni1F38 2605 def +/uni1F39 2606 def +/uni1F3A 2607 def +/uni1F3B 2608 def +/uni1F3C 2609 def +/uni1F3D 2610 def +/uni1F3E 2611 def +/uni1F3F 2612 def +/uni1F40 2613 def +/uni1F41 2614 def +/uni1F42 2615 def +/uni1F43 2616 def +/uni1F44 2617 def +/uni1F45 2618 def +/uni1F48 2619 def +/uni1F49 2620 def +/uni1F4A 2621 def +/uni1F4B 2622 def +/uni1F4C 2623 def +/uni1F4D 2624 def +/uni1F50 2625 def +/uni1F51 2626 def +/uni1F52 2627 def +/uni1F53 2628 def +/uni1F54 2629 def +/uni1F55 2630 def +/uni1F56 2631 def +/uni1F57 2632 def +/uni1F59 2633 def +/uni1F5B 2634 def +/uni1F5D 2635 def +/uni1F5F 2636 def +/uni1F60 2637 def +/uni1F61 2638 def +/uni1F62 2639 def +/uni1F63 2640 def +/uni1F64 2641 def +/uni1F65 2642 def +/uni1F66 2643 def +/uni1F67 2644 def +/uni1F68 2645 def +/uni1F69 2646 def +/uni1F6A 2647 def +/uni1F6B 2648 def +/uni1F6C 2649 def +/uni1F6D 2650 def +/uni1F6E 2651 def +/uni1F6F 2652 def +/uni1F70 2653 def +/uni1F71 2654 def +/uni1F72 2655 def +/uni1F73 2656 def +/uni1F74 2657 def +/uni1F75 2658 def +/uni1F76 2659 def +/uni1F77 2660 def +/uni1F78 2661 def +/uni1F79 2662 def +/uni1F7A 2663 def +/uni1F7B 2664 def +/uni1F7C 2665 def +/uni1F7D 2666 def +/uni1F80 2667 def +/uni1F81 2668 def +/uni1F82 2669 def +/uni1F83 2670 def +/uni1F84 2671 def +/uni1F85 2672 def +/uni1F86 2673 def +/uni1F87 2674 def +/uni1F88 2675 def +/uni1F89 2676 def +/uni1F8A 2677 def +/uni1F8B 2678 def +/uni1F8C 2679 def +/uni1F8D 2680 def +/uni1F8E 2681 def +/uni1F8F 2682 def +/uni1F90 2683 def +/uni1F91 2684 def +/uni1F92 2685 def +/uni1F93 2686 def +/uni1F94 2687 def +/uni1F95 2688 def +/uni1F96 2689 def +/uni1F97 2690 def +/uni1F98 2691 def +/uni1F99 2692 def +/uni1F9A 2693 def +/uni1F9B 2694 def +/uni1F9C 2695 def +/uni1F9D 2696 def +/uni1F9E 2697 def +/uni1F9F 2698 def +/uni1FA0 2699 def +/uni1FA1 2700 def +/uni1FA2 2701 def +/uni1FA3 2702 def +/uni1FA4 2703 def +/uni1FA5 2704 def +/uni1FA6 2705 def +/uni1FA7 2706 def +/uni1FA8 2707 def +/uni1FA9 2708 def +/uni1FAA 2709 def +/uni1FAB 2710 def +/uni1FAC 2711 def +/uni1FAD 2712 def +/uni1FAE 2713 def +/uni1FAF 2714 def +/uni1FB0 2715 def +/uni1FB1 2716 def +/uni1FB2 2717 def +/uni1FB3 2718 def +/uni1FB4 2719 def +/uni1FB6 2720 def +/uni1FB7 2721 def +/uni1FB8 2722 def +/uni1FB9 2723 def +/uni1FBA 2724 def +/uni1FBB 2725 def +/uni1FBC 2726 def +/uni1FBD 2727 def +/uni1FBE 2728 def +/uni1FBF 2729 def +/uni1FC0 2730 def +/uni1FC1 2731 def +/uni1FC2 2732 def +/uni1FC3 2733 def +/uni1FC4 2734 def +/uni1FC6 2735 def +/uni1FC7 2736 def +/uni1FC8 2737 def +/uni1FC9 2738 def +/uni1FCA 2739 def +/uni1FCB 2740 def +/uni1FCC 2741 def +/uni1FCD 2742 def +/uni1FCE 2743 def +/uni1FCF 2744 def +/uni1FD0 2745 def +/uni1FD1 2746 def +/uni1FD2 2747 def +/uni1FD3 2748 def +/uni1FD6 2749 def +/uni1FD7 2750 def +/uni1FD8 2751 def +/uni1FD9 2752 def +/uni1FDA 2753 def +/uni1FDB 2754 def +/uni1FDD 2755 def +/uni1FDE 2756 def +/uni1FDF 2757 def +/uni1FE0 2758 def +/uni1FE1 2759 def +/uni1FE2 2760 def +/uni1FE3 2761 def +/uni1FE4 2762 def +/uni1FE5 2763 def +/uni1FE6 2764 def +/uni1FE7 2765 def +/uni1FE8 2766 def +/uni1FE9 2767 def +/uni1FEA 2768 def +/uni1FEB 2769 def +/uni1FEC 2770 def +/uni1FED 2771 def +/uni1FEE 2772 def +/uni1FEF 2773 def +/uni1FF2 2774 def +/uni1FF3 2775 def +/uni1FF4 2776 def +/uni1FF6 2777 def +/uni1FF7 2778 def +/uni1FF8 2779 def +/uni1FF9 2780 def +/uni1FFA 2781 def +/uni1FFB 2782 def +/uni1FFC 2783 def +/uni1FFD 2784 def +/uni1FFE 2785 def +/uni2000 2786 def +/uni2001 2787 def +/uni2002 2788 def +/uni2003 2789 def +/uni2004 2790 def +/uni2005 2791 def +/uni2006 2792 def +/uni2007 2793 def +/uni2008 2794 def +/uni2009 2795 def +/uni200A 2796 def +/uni200B 2797 def +/uni200C 2798 def +/uni200D 2799 def +/uni200E 2800 def +/uni200F 2801 def +/uni2010 2802 def +/uni2011 2803 def +/figuredash 2804 def +/endash 2805 def +/emdash 2806 def +/uni2015 2807 def +/uni2016 2808 def +/underscoredbl 2809 def +/quoteleft 2810 def +/quoteright 2811 def +/quotesinglbase 2812 def +/quotereversed 2813 def +/quotedblleft 2814 def +/quotedblright 2815 def +/quotedblbase 2816 def +/uni201F 2817 def +/dagger 2818 def +/daggerdbl 2819 def +/bullet 2820 def +/uni2023 2821 def +/onedotenleader 2822 def +/twodotenleader 2823 def +/ellipsis 2824 def +/uni2027 2825 def +/uni2028 2826 def +/uni2029 2827 def +/uni202A 2828 def +/uni202B 2829 def +/uni202C 2830 def +/uni202D 2831 def +/uni202E 2832 def +/uni202F 2833 def +/perthousand 2834 def +/uni2031 2835 def +/minute 2836 def +/second 2837 def +/uni2034 2838 def +/uni2035 2839 def +/uni2036 2840 def +/uni2037 2841 def +/uni2038 2842 def +/guilsinglleft 2843 def +/guilsinglright 2844 def +/uni203B 2845 def +/exclamdbl 2846 def +/uni203D 2847 def +/uni203E 2848 def +/uni203F 2849 def +/uni2040 2850 def +/uni2041 2851 def +/uni2042 2852 def +/uni2043 2853 def +/fraction 2854 def +/uni2045 2855 def +/uni2046 2856 def +/uni2047 2857 def +/uni2048 2858 def +/uni2049 2859 def +/uni204A 2860 def +/uni204B 2861 def +/uni204C 2862 def +/uni204D 2863 def +/uni204E 2864 def +/uni204F 2865 def +/uni2050 2866 def +/uni2051 2867 def +/uni2052 2868 def +/uni2053 2869 def +/uni2054 2870 def +/uni2055 2871 def +/uni2056 2872 def +/uni2057 2873 def +/uni2058 2874 def +/uni2059 2875 def +/uni205A 2876 def +/uni205B 2877 def +/uni205C 2878 def +/uni205D 2879 def +/uni205E 2880 def +/uni205F 2881 def +/uni2060 2882 def +/uni2061 2883 def +/uni2062 2884 def +/uni2063 2885 def +/uni2064 2886 def +/uni206A 2887 def +/uni206B 2888 def +/uni206C 2889 def +/uni206D 2890 def +/uni206E 2891 def +/uni206F 2892 def +/uni2070 2893 def +/uni2071 2894 def +/uni2074 2895 def +/uni2075 2896 def +/uni2076 2897 def +/uni2077 2898 def +/uni2078 2899 def +/uni2079 2900 def +/uni207A 2901 def +/uni207B 2902 def +/uni207C 2903 def +/uni207D 2904 def +/uni207E 2905 def +/uni207F 2906 def +/uni2080 2907 def +/uni2081 2908 def +/uni2082 2909 def +/uni2083 2910 def +/uni2084 2911 def +/uni2085 2912 def +/uni2086 2913 def +/uni2087 2914 def +/uni2088 2915 def +/uni2089 2916 def +/uni208A 2917 def +/uni208B 2918 def +/uni208C 2919 def +/uni208D 2920 def +/uni208E 2921 def +/uni2090 2922 def +/uni2091 2923 def +/uni2092 2924 def +/uni2093 2925 def +/uni2094 2926 def +/uni2095 2927 def +/uni2096 2928 def +/uni2097 2929 def +/uni2098 2930 def +/uni2099 2931 def +/uni209A 2932 def +/uni209B 2933 def +/uni209C 2934 def +/uni20A0 2935 def +/colonmonetary 2936 def +/uni20A2 2937 def +/franc 2938 def +/lira 2939 def +/uni20A5 2940 def +/uni20A6 2941 def +/peseta 2942 def +/uni20A8 2943 def +/uni20A9 2944 def +/uni20AA 2945 def +/dong 2946 def +/Euro 2947 def +/uni20AD 2948 def +/uni20AE 2949 def +/uni20AF 2950 def +/uni20B0 2951 def +/uni20B1 2952 def +/uni20B2 2953 def +/uni20B3 2954 def +/uni20B4 2955 def +/uni20B5 2956 def +/uni20B8 2957 def +/uni20B9 2958 def +/uni20BA 2959 def +/uni20BD 2960 def +/uni20D0 2961 def +/uni20D1 2962 def +/uni20D6 2963 def +/uni20D7 2964 def +/uni20DB 2965 def +/uni20DC 2966 def +/uni20E1 2967 def +/uni2100 2968 def +/uni2101 2969 def +/uni2102 2970 def +/uni2103 2971 def +/uni2104 2972 def +/uni2105 2973 def +/uni2106 2974 def +/uni2107 2975 def +/uni2108 2976 def +/uni2109 2977 def +/uni210B 2978 def +/uni210C 2979 def +/uni210D 2980 def +/uni210E 2981 def +/uni210F 2982 def +/uni2110 2983 def +/Ifraktur 2984 def +/uni2112 2985 def +/uni2113 2986 def +/uni2114 2987 def +/uni2115 2988 def +/uni2116 2989 def +/uni2117 2990 def +/weierstrass 2991 def +/uni2119 2992 def +/uni211A 2993 def +/uni211B 2994 def +/Rfraktur 2995 def +/uni211D 2996 def +/prescription 2997 def +/uni211F 2998 def +/uni2120 2999 def +/uni2121 3000 def +/trademark 3001 def +/uni2123 3002 def +/uni2124 3003 def +/uni2125 3004 def +/uni2126 3005 def +/uni2127 3006 def +/uni2128 3007 def +/uni2129 3008 def +/uni212A 3009 def +/uni212B 3010 def +/uni212C 3011 def +/uni212D 3012 def +/estimated 3013 def +/uni212F 3014 def +/uni2130 3015 def +/uni2131 3016 def +/uni2132 3017 def +/uni2133 3018 def +/uni2134 3019 def +/aleph 3020 def +/uni2136 3021 def +/uni2137 3022 def +/uni2138 3023 def +/uni2139 3024 def +/uni213A 3025 def +/uni213B 3026 def +/uni213C 3027 def +/uni213D 3028 def +/uni213E 3029 def +/uni213F 3030 def +/uni2140 3031 def +/uni2141 3032 def +/uni2142 3033 def +/uni2143 3034 def +/uni2144 3035 def +/uni2145 3036 def +/uni2146 3037 def +/uni2147 3038 def +/uni2148 3039 def +/uni2149 3040 def +/uni214B 3041 def +/uni214E 3042 def +/uni2150 3043 def +/uni2151 3044 def +/uni2152 3045 def +/onethird 3046 def +/twothirds 3047 def +/uni2155 3048 def +/uni2156 3049 def +/uni2157 3050 def +/uni2158 3051 def +/uni2159 3052 def +/uni215A 3053 def +/oneeighth 3054 def +/threeeighths 3055 def +/fiveeighths 3056 def +/seveneighths 3057 def +/uni215F 3058 def +/uni2160 3059 def +/uni2161 3060 def +/uni2162 3061 def +/uni2163 3062 def +/uni2164 3063 def +/uni2165 3064 def +/uni2166 3065 def +/uni2167 3066 def +/uni2168 3067 def +/uni2169 3068 def +/uni216A 3069 def +/uni216B 3070 def +/uni216C 3071 def +/uni216D 3072 def +/uni216E 3073 def +/uni216F 3074 def +/uni2170 3075 def +/uni2171 3076 def +/uni2172 3077 def +/uni2173 3078 def +/uni2174 3079 def +/uni2175 3080 def +/uni2176 3081 def +/uni2177 3082 def +/uni2178 3083 def +/uni2179 3084 def +/uni217A 3085 def +/uni217B 3086 def +/uni217C 3087 def +/uni217D 3088 def +/uni217E 3089 def +/uni217F 3090 def +/uni2180 3091 def +/uni2181 3092 def +/uni2182 3093 def +/uni2183 3094 def +/uni2184 3095 def +/uni2185 3096 def +/uni2189 3097 def +/arrowleft 3098 def +/arrowup 3099 def +/arrowright 3100 def +/arrowdown 3101 def +/arrowboth 3102 def +/arrowupdn 3103 def +/uni2196 3104 def +/uni2197 3105 def +/uni2198 3106 def +/uni2199 3107 def +/uni219A 3108 def +/uni219B 3109 def +/uni219C 3110 def +/uni219D 3111 def +/uni219E 3112 def +/uni219F 3113 def +/uni21A0 3114 def +/uni21A1 3115 def +/uni21A2 3116 def +/uni21A3 3117 def +/uni21A4 3118 def +/uni21A5 3119 def +/uni21A6 3120 def +/uni21A7 3121 def +/arrowupdnbse 3122 def +/uni21A9 3123 def +/uni21AA 3124 def +/uni21AB 3125 def +/uni21AC 3126 def +/uni21AD 3127 def +/uni21AE 3128 def +/uni21AF 3129 def +/uni21B0 3130 def +/uni21B1 3131 def +/uni21B2 3132 def +/uni21B3 3133 def +/uni21B4 3134 def +/carriagereturn 3135 def +/uni21B6 3136 def +/uni21B7 3137 def +/uni21B8 3138 def +/uni21B9 3139 def +/uni21BA 3140 def +/uni21BB 3141 def +/uni21BC 3142 def +/uni21BD 3143 def +/uni21BE 3144 def +/uni21BF 3145 def +/uni21C0 3146 def +/uni21C1 3147 def +/uni21C2 3148 def +/uni21C3 3149 def +/uni21C4 3150 def +/uni21C5 3151 def +/uni21C6 3152 def +/uni21C7 3153 def +/uni21C8 3154 def +/uni21C9 3155 def +/uni21CA 3156 def +/uni21CB 3157 def +/uni21CC 3158 def +/uni21CD 3159 def +/uni21CE 3160 def +/uni21CF 3161 def +/arrowdblleft 3162 def +/arrowdblup 3163 def +/arrowdblright 3164 def +/arrowdbldown 3165 def +/arrowdblboth 3166 def +/uni21D5 3167 def +/uni21D6 3168 def +/uni21D7 3169 def +/uni21D8 3170 def +/uni21D9 3171 def +/uni21DA 3172 def +/uni21DB 3173 def +/uni21DC 3174 def +/uni21DD 3175 def +/uni21DE 3176 def +/uni21DF 3177 def +/uni21E0 3178 def +/uni21E1 3179 def +/uni21E2 3180 def +/uni21E3 3181 def +/uni21E4 3182 def +/uni21E5 3183 def +/uni21E6 3184 def +/uni21E7 3185 def +/uni21E8 3186 def +/uni21E9 3187 def +/uni21EA 3188 def +/uni21EB 3189 def +/uni21EC 3190 def +/uni21ED 3191 def +/uni21EE 3192 def +/uni21EF 3193 def +/uni21F0 3194 def +/uni21F1 3195 def +/uni21F2 3196 def +/uni21F3 3197 def +/uni21F4 3198 def +/uni21F5 3199 def +/uni21F6 3200 def +/uni21F7 3201 def +/uni21F8 3202 def +/uni21F9 3203 def +/uni21FA 3204 def +/uni21FB 3205 def +/uni21FC 3206 def +/uni21FD 3207 def +/uni21FE 3208 def +/uni21FF 3209 def +/universal 3210 def +/uni2201 3211 def +/partialdiff 3212 def +/existential 3213 def +/uni2204 3214 def +/emptyset 3215 def +/Delta 3216 def +/gradient 3217 def +/element 3218 def +/notelement 3219 def +/uni220A 3220 def +/suchthat 3221 def +/uni220C 3222 def +/uni220D 3223 def +/uni220E 3224 def +/product 3225 def +/uni2210 3226 def +/summation 3227 def +/minus 3228 def +/uni2213 3229 def +/uni2214 3230 def +/uni2215 3231 def +/uni2216 3232 def +/asteriskmath 3233 def +/uni2218 3234 def +/uni2219 3235 def +/radical 3236 def +/uni221B 3237 def +/uni221C 3238 def +/proportional 3239 def +/infinity 3240 def +/orthogonal 3241 def +/angle 3242 def +/uni2221 3243 def +/uni2222 3244 def +/uni2223 3245 def +/uni2224 3246 def +/uni2225 3247 def +/uni2226 3248 def +/logicaland 3249 def +/logicalor 3250 def +/intersection 3251 def +/union 3252 def +/integral 3253 def +/uni222C 3254 def +/uni222D 3255 def +/uni222E 3256 def +/uni222F 3257 def +/uni2230 3258 def +/uni2231 3259 def +/uni2232 3260 def +/uni2233 3261 def +/therefore 3262 def +/uni2235 3263 def +/uni2236 3264 def +/uni2237 3265 def +/uni2238 3266 def +/uni2239 3267 def +/uni223A 3268 def +/uni223B 3269 def +/similar 3270 def +/uni223D 3271 def +/uni223E 3272 def +/uni223F 3273 def +/uni2240 3274 def +/uni2241 3275 def +/uni2242 3276 def +/uni2243 3277 def +/uni2244 3278 def +/congruent 3279 def +/uni2246 3280 def +/uni2247 3281 def +/approxequal 3282 def +/uni2249 3283 def +/uni224A 3284 def +/uni224B 3285 def +/uni224C 3286 def +/uni224D 3287 def +/uni224E 3288 def +/uni224F 3289 def +/uni2250 3290 def +/uni2251 3291 def +/uni2252 3292 def +/uni2253 3293 def +/uni2254 3294 def +/uni2255 3295 def +/uni2256 3296 def +/uni2257 3297 def +/uni2258 3298 def +/uni2259 3299 def +/uni225A 3300 def +/uni225B 3301 def +/uni225C 3302 def +/uni225D 3303 def +/uni225E 3304 def +/uni225F 3305 def +/notequal 3306 def +/equivalence 3307 def +/uni2262 3308 def +/uni2263 3309 def +/lessequal 3310 def +/greaterequal 3311 def +/uni2266 3312 def +/uni2267 3313 def +/uni2268 3314 def +/uni2269 3315 def +/uni226A 3316 def +/uni226B 3317 def +/uni226C 3318 def +/uni226D 3319 def +/uni226E 3320 def +/uni226F 3321 def +/uni2270 3322 def +/uni2271 3323 def +/uni2272 3324 def +/uni2273 3325 def +/uni2274 3326 def +/uni2275 3327 def +/uni2276 3328 def +/uni2277 3329 def +/uni2278 3330 def +/uni2279 3331 def +/uni227A 3332 def +/uni227B 3333 def +/uni227C 3334 def +/uni227D 3335 def +/uni227E 3336 def +/uni227F 3337 def +/uni2280 3338 def +/uni2281 3339 def +/propersubset 3340 def +/propersuperset 3341 def +/notsubset 3342 def +/uni2285 3343 def +/reflexsubset 3344 def +/reflexsuperset 3345 def +/uni2288 3346 def +/uni2289 3347 def +/uni228A 3348 def +/uni228B 3349 def +/uni228C 3350 def +/uni228D 3351 def +/uni228E 3352 def +/uni228F 3353 def +/uni2290 3354 def +/uni2291 3355 def +/uni2292 3356 def +/uni2293 3357 def +/uni2294 3358 def +/circleplus 3359 def +/uni2296 3360 def +/circlemultiply 3361 def +/uni2298 3362 def +/uni2299 3363 def +/uni229A 3364 def +/uni229B 3365 def +/uni229C 3366 def +/uni229D 3367 def +/uni229E 3368 def +/uni229F 3369 def +/uni22A0 3370 def +/uni22A1 3371 def +/uni22A2 3372 def +/uni22A3 3373 def +/uni22A4 3374 def +/perpendicular 3375 def +/uni22A6 3376 def +/uni22A7 3377 def +/uni22A8 3378 def +/uni22A9 3379 def +/uni22AA 3380 def +/uni22AB 3381 def +/uni22AC 3382 def +/uni22AD 3383 def +/uni22AE 3384 def +/uni22AF 3385 def +/uni22B0 3386 def +/uni22B1 3387 def +/uni22B2 3388 def +/uni22B3 3389 def +/uni22B4 3390 def +/uni22B5 3391 def +/uni22B6 3392 def +/uni22B7 3393 def +/uni22B8 3394 def +/uni22B9 3395 def +/uni22BA 3396 def +/uni22BB 3397 def +/uni22BC 3398 def +/uni22BD 3399 def +/uni22BE 3400 def +/uni22BF 3401 def +/uni22C0 3402 def +/uni22C1 3403 def +/uni22C2 3404 def +/uni22C3 3405 def +/uni22C4 3406 def +/dotmath 3407 def +/uni22C6 3408 def +/uni22C7 3409 def +/uni22C8 3410 def +/uni22C9 3411 def +/uni22CA 3412 def +/uni22CB 3413 def +/uni22CC 3414 def +/uni22CD 3415 def +/uni22CE 3416 def +/uni22CF 3417 def +/uni22D0 3418 def +/uni22D1 3419 def +/uni22D2 3420 def +/uni22D3 3421 def +/uni22D4 3422 def +/uni22D5 3423 def +/uni22D6 3424 def +/uni22D7 3425 def +/uni22D8 3426 def +/uni22D9 3427 def +/uni22DA 3428 def +/uni22DB 3429 def +/uni22DC 3430 def +/uni22DD 3431 def +/uni22DE 3432 def +/uni22DF 3433 def +/uni22E0 3434 def +/uni22E1 3435 def +/uni22E2 3436 def +/uni22E3 3437 def +/uni22E4 3438 def +/uni22E5 3439 def +/uni22E6 3440 def +/uni22E7 3441 def +/uni22E8 3442 def +/uni22E9 3443 def +/uni22EA 3444 def +/uni22EB 3445 def +/uni22EC 3446 def +/uni22ED 3447 def +/uni22EE 3448 def +/uni22EF 3449 def +/uni22F0 3450 def +/uni22F1 3451 def +/uni22F2 3452 def +/uni22F3 3453 def +/uni22F4 3454 def +/uni22F5 3455 def +/uni22F6 3456 def +/uni22F7 3457 def +/uni22F8 3458 def +/uni22F9 3459 def +/uni22FA 3460 def +/uni22FB 3461 def +/uni22FC 3462 def +/uni22FD 3463 def +/uni22FE 3464 def +/uni22FF 3465 def +/uni2300 3466 def +/uni2301 3467 def +/house 3468 def +/uni2303 3469 def +/uni2304 3470 def +/uni2305 3471 def +/uni2306 3472 def +/uni2307 3473 def +/uni2308 3474 def +/uni2309 3475 def +/uni230A 3476 def +/uni230B 3477 def +/uni230C 3478 def +/uni230D 3479 def +/uni230E 3480 def +/uni230F 3481 def +/revlogicalnot 3482 def +/uni2311 3483 def +/uni2318 3484 def +/uni2319 3485 def +/uni231C 3486 def +/uni231D 3487 def +/uni231E 3488 def +/uni231F 3489 def +/integraltp 3490 def +/integralbt 3491 def +/uni2324 3492 def +/uni2325 3493 def +/uni2326 3494 def +/uni2327 3495 def +/uni2328 3496 def +/uni232B 3497 def +/uni232C 3498 def +/uni2373 3499 def +/uni2374 3500 def +/uni2375 3501 def +/uni237A 3502 def +/uni237D 3503 def +/uni2387 3504 def +/uni2394 3505 def +/uni239B 3506 def +/uni239C 3507 def +/uni239D 3508 def +/uni239E 3509 def +/uni239F 3510 def +/uni23A0 3511 def +/uni23A1 3512 def +/uni23A2 3513 def +/uni23A3 3514 def +/uni23A4 3515 def +/uni23A5 3516 def +/uni23A6 3517 def +/uni23A7 3518 def +/uni23A8 3519 def +/uni23A9 3520 def +/uni23AA 3521 def +/uni23AB 3522 def +/uni23AC 3523 def +/uni23AD 3524 def +/uni23AE 3525 def +/uni23CE 3526 def +/uni23CF 3527 def +/uni23E3 3528 def +/uni23E5 3529 def +/uni23E8 3530 def +/uni2422 3531 def +/uni2423 3532 def +/uni2460 3533 def +/uni2461 3534 def +/uni2462 3535 def +/uni2463 3536 def +/uni2464 3537 def +/uni2465 3538 def +/uni2466 3539 def +/uni2467 3540 def +/uni2468 3541 def +/uni2469 3542 def +/SF100000 3543 def +/uni2501 3544 def +/SF110000 3545 def +/uni2503 3546 def +/uni2504 3547 def +/uni2505 3548 def +/uni2506 3549 def +/uni2507 3550 def +/uni2508 3551 def +/uni2509 3552 def +/uni250A 3553 def +/uni250B 3554 def +/SF010000 3555 def +/uni250D 3556 def +/uni250E 3557 def +/uni250F 3558 def +/SF030000 3559 def +/uni2511 3560 def +/uni2512 3561 def +/uni2513 3562 def +/SF020000 3563 def +/uni2515 3564 def +/uni2516 3565 def +/uni2517 3566 def +/SF040000 3567 def +/uni2519 3568 def +/uni251A 3569 def +/uni251B 3570 def +/SF080000 3571 def +/uni251D 3572 def +/uni251E 3573 def +/uni251F 3574 def +/uni2520 3575 def +/uni2521 3576 def +/uni2522 3577 def +/uni2523 3578 def +/SF090000 3579 def +/uni2525 3580 def +/uni2526 3581 def +/uni2527 3582 def +/uni2528 3583 def +/uni2529 3584 def +/uni252A 3585 def +/uni252B 3586 def +/SF060000 3587 def +/uni252D 3588 def +/uni252E 3589 def +/uni252F 3590 def +/uni2530 3591 def +/uni2531 3592 def +/uni2532 3593 def +/uni2533 3594 def +/SF070000 3595 def +/uni2535 3596 def +/uni2536 3597 def +/uni2537 3598 def +/uni2538 3599 def +/uni2539 3600 def +/uni253A 3601 def +/uni253B 3602 def +/SF050000 3603 def +/uni253D 3604 def +/uni253E 3605 def +/uni253F 3606 def +/uni2540 3607 def +/uni2541 3608 def +/uni2542 3609 def +/uni2543 3610 def +/uni2544 3611 def +/uni2545 3612 def +/uni2546 3613 def +/uni2547 3614 def +/uni2548 3615 def +/uni2549 3616 def +/uni254A 3617 def +/uni254B 3618 def +/uni254C 3619 def +/uni254D 3620 def +/uni254E 3621 def +/uni254F 3622 def +/SF430000 3623 def +/SF240000 3624 def +/SF510000 3625 def +/SF520000 3626 def +/SF390000 3627 def +/SF220000 3628 def +/SF210000 3629 def +/SF250000 3630 def +/SF500000 3631 def +/SF490000 3632 def +/SF380000 3633 def +/SF280000 3634 def +/SF270000 3635 def +/SF260000 3636 def +/SF360000 3637 def +/SF370000 3638 def +/SF420000 3639 def +/SF190000 3640 def +/SF200000 3641 def +/SF230000 3642 def +/SF470000 3643 def +/SF480000 3644 def +/SF410000 3645 def +/SF450000 3646 def +/SF460000 3647 def +/SF400000 3648 def +/SF540000 3649 def +/SF530000 3650 def +/SF440000 3651 def +/uni256D 3652 def +/uni256E 3653 def +/uni256F 3654 def +/uni2570 3655 def +/uni2571 3656 def +/uni2572 3657 def +/uni2573 3658 def +/uni2574 3659 def +/uni2575 3660 def +/uni2576 3661 def +/uni2577 3662 def +/uni2578 3663 def +/uni2579 3664 def +/uni257A 3665 def +/uni257B 3666 def +/uni257C 3667 def +/uni257D 3668 def +/uni257E 3669 def +/uni257F 3670 def +/upblock 3671 def +/uni2581 3672 def +/uni2582 3673 def +/uni2583 3674 def +/dnblock 3675 def +/uni2585 3676 def +/uni2586 3677 def +/uni2587 3678 def +/block 3679 def +/uni2589 3680 def +/uni258A 3681 def +/uni258B 3682 def +/lfblock 3683 def +/uni258D 3684 def +/uni258E 3685 def +/uni258F 3686 def +/rtblock 3687 def +/ltshade 3688 def +/shade 3689 def +/dkshade 3690 def +/uni2594 3691 def +/uni2595 3692 def +/uni2596 3693 def +/uni2597 3694 def +/uni2598 3695 def +/uni2599 3696 def +/uni259A 3697 def +/uni259B 3698 def +/uni259C 3699 def +/uni259D 3700 def +/uni259E 3701 def +/uni259F 3702 def +/filledbox 3703 def +/H22073 3704 def +/uni25A2 3705 def +/uni25A3 3706 def +/uni25A4 3707 def +/uni25A5 3708 def +/uni25A6 3709 def +/uni25A7 3710 def +/uni25A8 3711 def +/uni25A9 3712 def +/H18543 3713 def +/H18551 3714 def +/filledrect 3715 def +/uni25AD 3716 def +/uni25AE 3717 def +/uni25AF 3718 def +/uni25B0 3719 def +/uni25B1 3720 def +/triagup 3721 def +/uni25B3 3722 def +/uni25B4 3723 def +/uni25B5 3724 def +/uni25B6 3725 def +/uni25B7 3726 def +/uni25B8 3727 def +/uni25B9 3728 def +/triagrt 3729 def +/uni25BB 3730 def +/triagdn 3731 def +/uni25BD 3732 def +/uni25BE 3733 def +/uni25BF 3734 def +/uni25C0 3735 def +/uni25C1 3736 def +/uni25C2 3737 def +/uni25C3 3738 def +/triaglf 3739 def +/uni25C5 3740 def +/uni25C6 3741 def +/uni25C7 3742 def +/uni25C8 3743 def +/uni25C9 3744 def +/lozenge 3745 def +/circle 3746 def +/uni25CC 3747 def +/uni25CD 3748 def +/uni25CE 3749 def +/H18533 3750 def +/uni25D0 3751 def +/uni25D1 3752 def +/uni25D2 3753 def +/uni25D3 3754 def +/uni25D4 3755 def +/uni25D5 3756 def +/uni25D6 3757 def +/uni25D7 3758 def +/invbullet 3759 def +/invcircle 3760 def +/uni25DA 3761 def +/uni25DB 3762 def +/uni25DC 3763 def +/uni25DD 3764 def +/uni25DE 3765 def +/uni25DF 3766 def +/uni25E0 3767 def +/uni25E1 3768 def +/uni25E2 3769 def +/uni25E3 3770 def +/uni25E4 3771 def +/uni25E5 3772 def +/openbullet 3773 def +/uni25E7 3774 def +/uni25E8 3775 def +/uni25E9 3776 def +/uni25EA 3777 def +/uni25EB 3778 def +/uni25EC 3779 def +/uni25ED 3780 def +/uni25EE 3781 def +/uni25EF 3782 def +/uni25F0 3783 def +/uni25F1 3784 def +/uni25F2 3785 def +/uni25F3 3786 def +/uni25F4 3787 def +/uni25F5 3788 def +/uni25F6 3789 def +/uni25F7 3790 def +/uni25F8 3791 def +/uni25F9 3792 def +/uni25FA 3793 def +/uni25FB 3794 def +/uni25FC 3795 def +/uni25FD 3796 def +/uni25FE 3797 def +/uni25FF 3798 def +/uni2600 3799 def +/uni2601 3800 def +/uni2602 3801 def +/uni2603 3802 def +/uni2604 3803 def +/uni2605 3804 def +/uni2606 3805 def +/uni2607 3806 def +/uni2608 3807 def +/uni2609 3808 def +/uni260A 3809 def +/uni260B 3810 def +/uni260C 3811 def +/uni260D 3812 def +/uni260E 3813 def +/uni260F 3814 def +/uni2610 3815 def +/uni2611 3816 def +/uni2612 3817 def +/uni2613 3818 def +/uni2614 3819 def +/uni2615 3820 def +/uni2616 3821 def +/uni2617 3822 def +/uni2618 3823 def +/uni2619 3824 def +/uni261A 3825 def +/uni261B 3826 def +/uni261C 3827 def +/uni261D 3828 def +/uni261E 3829 def +/uni261F 3830 def +/uni2620 3831 def +/uni2621 3832 def +/uni2622 3833 def +/uni2623 3834 def +/uni2624 3835 def +/uni2625 3836 def +/uni2626 3837 def +/uni2627 3838 def +/uni2628 3839 def +/uni2629 3840 def +/uni262A 3841 def +/uni262B 3842 def +/uni262C 3843 def +/uni262D 3844 def +/uni262E 3845 def +/uni262F 3846 def +/uni2630 3847 def +/uni2631 3848 def +/uni2632 3849 def +/uni2633 3850 def +/uni2634 3851 def +/uni2635 3852 def +/uni2636 3853 def +/uni2637 3854 def +/uni2638 3855 def +/uni2639 3856 def +/smileface 3857 def +/invsmileface 3858 def +/sun 3859 def +/uni263D 3860 def +/uni263E 3861 def +/uni263F 3862 def +/female 3863 def +/uni2641 3864 def +/male 3865 def +/uni2643 3866 def +/uni2644 3867 def +/uni2645 3868 def +/uni2646 3869 def +/uni2647 3870 def +/uni2648 3871 def +/uni2649 3872 def +/uni264A 3873 def +/uni264B 3874 def +/uni264C 3875 def +/uni264D 3876 def +/uni264E 3877 def +/uni264F 3878 def +/uni2650 3879 def +/uni2651 3880 def +/uni2652 3881 def +/uni2653 3882 def +/uni2654 3883 def +/uni2655 3884 def +/uni2656 3885 def +/uni2657 3886 def +/uni2658 3887 def +/uni2659 3888 def +/uni265A 3889 def +/uni265B 3890 def +/uni265C 3891 def +/uni265D 3892 def +/uni265E 3893 def +/uni265F 3894 def +/spade 3895 def +/uni2661 3896 def +/uni2662 3897 def +/club 3898 def +/uni2664 3899 def +/heart 3900 def +/diamond 3901 def +/uni2667 3902 def +/uni2668 3903 def +/uni2669 3904 def +/musicalnote 3905 def +/musicalnotedbl 3906 def +/uni266C 3907 def +/uni266D 3908 def +/uni266E 3909 def +/uni266F 3910 def +/uni2670 3911 def +/uni2671 3912 def +/uni2672 3913 def +/uni2673 3914 def +/uni2674 3915 def +/uni2675 3916 def +/uni2676 3917 def +/uni2677 3918 def +/uni2678 3919 def +/uni2679 3920 def +/uni267A 3921 def +/uni267B 3922 def +/uni267C 3923 def +/uni267D 3924 def +/uni267E 3925 def +/uni267F 3926 def +/uni2680 3927 def +/uni2681 3928 def +/uni2682 3929 def +/uni2683 3930 def +/uni2684 3931 def +/uni2685 3932 def +/uni2686 3933 def +/uni2687 3934 def +/uni2688 3935 def +/uni2689 3936 def +/uni268A 3937 def +/uni268B 3938 def +/uni268C 3939 def +/uni268D 3940 def +/uni268E 3941 def +/uni268F 3942 def +/uni2690 3943 def +/uni2691 3944 def +/uni2692 3945 def +/uni2693 3946 def +/uni2694 3947 def +/uni2695 3948 def +/uni2696 3949 def +/uni2697 3950 def +/uni2698 3951 def +/uni2699 3952 def +/uni269A 3953 def +/uni269B 3954 def +/uni269C 3955 def +/uni269E 3956 def +/uni269F 3957 def +/uni26A0 3958 def +/uni26A1 3959 def +/uni26A2 3960 def +/uni26A3 3961 def +/uni26A4 3962 def +/uni26A5 3963 def +/uni26A6 3964 def +/uni26A7 3965 def +/uni26A8 3966 def +/uni26A9 3967 def +/uni26AA 3968 def +/uni26AB 3969 def +/uni26AC 3970 def +/uni26AD 3971 def +/uni26AE 3972 def +/uni26AF 3973 def +/uni26B0 3974 def +/uni26B1 3975 def +/uni26B2 3976 def +/uni26B3 3977 def +/uni26B4 3978 def +/uni26B5 3979 def +/uni26B6 3980 def +/uni26B7 3981 def +/uni26B8 3982 def +/uni26C0 3983 def +/uni26C1 3984 def +/uni26C2 3985 def +/uni26C3 3986 def +/uni26E2 3987 def +/uni2701 3988 def +/uni2702 3989 def +/uni2703 3990 def +/uni2704 3991 def +/uni2706 3992 def +/uni2707 3993 def +/uni2708 3994 def +/uni2709 3995 def +/uni270C 3996 def +/uni270D 3997 def +/uni270E 3998 def +/uni270F 3999 def +/uni2710 4000 def +/uni2711 4001 def +/uni2712 4002 def +/uni2713 4003 def +/uni2714 4004 def +/uni2715 4005 def +/uni2716 4006 def +/uni2717 4007 def +/uni2718 4008 def +/uni2719 4009 def +/uni271A 4010 def +/uni271B 4011 def +/uni271C 4012 def +/uni271D 4013 def +/uni271E 4014 def +/uni271F 4015 def +/uni2720 4016 def +/uni2721 4017 def +/uni2722 4018 def +/uni2723 4019 def +/uni2724 4020 def +/uni2725 4021 def +/uni2726 4022 def +/uni2727 4023 def +/uni2729 4024 def +/uni272A 4025 def +/uni272B 4026 def +/uni272C 4027 def +/uni272D 4028 def +/uni272E 4029 def +/uni272F 4030 def +/uni2730 4031 def +/uni2731 4032 def +/uni2732 4033 def +/uni2733 4034 def +/uni2734 4035 def +/uni2735 4036 def +/uni2736 4037 def +/uni2737 4038 def +/uni2738 4039 def +/uni2739 4040 def +/uni273A 4041 def +/uni273B 4042 def +/uni273C 4043 def +/uni273D 4044 def +/uni273E 4045 def +/uni273F 4046 def +/uni2740 4047 def +/uni2741 4048 def +/uni2742 4049 def +/uni2743 4050 def +/uni2744 4051 def +/uni2745 4052 def +/uni2746 4053 def +/uni2747 4054 def +/uni2748 4055 def +/uni2749 4056 def +/uni274A 4057 def +/uni274B 4058 def +/uni274D 4059 def +/uni274F 4060 def +/uni2750 4061 def +/uni2751 4062 def +/uni2752 4063 def +/uni2756 4064 def +/uni2758 4065 def +/uni2759 4066 def +/uni275A 4067 def +/uni275B 4068 def +/uni275C 4069 def +/uni275D 4070 def +/uni275E 4071 def +/uni2761 4072 def +/uni2762 4073 def +/uni2763 4074 def +/uni2764 4075 def +/uni2765 4076 def +/uni2766 4077 def +/uni2767 4078 def +/uni2768 4079 def +/uni2769 4080 def +/uni276A 4081 def +/uni276B 4082 def +/uni276C 4083 def +/uni276D 4084 def +/uni276E 4085 def +/uni276F 4086 def +/uni2770 4087 def +/uni2771 4088 def +/uni2772 4089 def +/uni2773 4090 def +/uni2774 4091 def +/uni2775 4092 def +/uni2776 4093 def +/uni2777 4094 def +/uni2778 4095 def +/uni2779 4096 def +/uni277A 4097 def +/uni277B 4098 def +/uni277C 4099 def +/uni277D 4100 def +/uni277E 4101 def +/uni277F 4102 def +/uni2780 4103 def +/uni2781 4104 def +/uni2782 4105 def +/uni2783 4106 def +/uni2784 4107 def +/uni2785 4108 def +/uni2786 4109 def +/uni2787 4110 def +/uni2788 4111 def +/uni2789 4112 def +/uni278A 4113 def +/uni278B 4114 def +/uni278C 4115 def +/uni278D 4116 def +/uni278E 4117 def +/uni278F 4118 def +/uni2790 4119 def +/uni2791 4120 def +/uni2792 4121 def +/uni2793 4122 def +/uni2794 4123 def +/uni2798 4124 def +/uni2799 4125 def +/uni279A 4126 def +/uni279B 4127 def +/uni279C 4128 def +/uni279D 4129 def +/uni279E 4130 def +/uni279F 4131 def +/uni27A0 4132 def +/uni27A1 4133 def +/uni27A2 4134 def +/uni27A3 4135 def +/uni27A4 4136 def +/uni27A5 4137 def +/uni27A6 4138 def +/uni27A7 4139 def +/uni27A8 4140 def +/uni27A9 4141 def +/uni27AA 4142 def +/uni27AB 4143 def +/uni27AC 4144 def +/uni27AD 4145 def +/uni27AE 4146 def +/uni27AF 4147 def +/uni27B1 4148 def +/uni27B2 4149 def +/uni27B3 4150 def +/uni27B4 4151 def +/uni27B5 4152 def +/uni27B6 4153 def +/uni27B7 4154 def +/uni27B8 4155 def +/uni27B9 4156 def +/uni27BA 4157 def +/uni27BB 4158 def +/uni27BC 4159 def +/uni27BD 4160 def +/uni27BE 4161 def +/uni27C5 4162 def +/uni27C6 4163 def +/uni27E0 4164 def +/uni27E6 4165 def +/uni27E7 4166 def +/uni27E8 4167 def +/uni27E9 4168 def +/uni27EA 4169 def +/uni27EB 4170 def +/uni27F0 4171 def +/uni27F1 4172 def +/uni27F2 4173 def +/uni27F3 4174 def +/uni27F4 4175 def +/uni27F5 4176 def +/uni27F6 4177 def +/uni27F7 4178 def +/uni27F8 4179 def +/uni27F9 4180 def +/uni27FA 4181 def +/uni27FB 4182 def +/uni27FC 4183 def +/uni27FD 4184 def +/uni27FE 4185 def +/uni27FF 4186 def +/uni2800 4187 def +/uni2801 4188 def +/uni2802 4189 def +/uni2803 4190 def +/uni2804 4191 def +/uni2805 4192 def +/uni2806 4193 def +/uni2807 4194 def +/uni2808 4195 def +/uni2809 4196 def +/uni280A 4197 def +/uni280B 4198 def +/uni280C 4199 def +/uni280D 4200 def +/uni280E 4201 def +/uni280F 4202 def +/uni2810 4203 def +/uni2811 4204 def +/uni2812 4205 def +/uni2813 4206 def +/uni2814 4207 def +/uni2815 4208 def +/uni2816 4209 def +/uni2817 4210 def +/uni2818 4211 def +/uni2819 4212 def +/uni281A 4213 def +/uni281B 4214 def +/uni281C 4215 def +/uni281D 4216 def +/uni281E 4217 def +/uni281F 4218 def +/uni2820 4219 def +/uni2821 4220 def +/uni2822 4221 def +/uni2823 4222 def +/uni2824 4223 def +/uni2825 4224 def +/uni2826 4225 def +/uni2827 4226 def +/uni2828 4227 def +/uni2829 4228 def +/uni282A 4229 def +/uni282B 4230 def +/uni282C 4231 def +/uni282D 4232 def +/uni282E 4233 def +/uni282F 4234 def +/uni2830 4235 def +/uni2831 4236 def +/uni2832 4237 def +/uni2833 4238 def +/uni2834 4239 def +/uni2835 4240 def +/uni2836 4241 def +/uni2837 4242 def +/uni2838 4243 def +/uni2839 4244 def +/uni283A 4245 def +/uni283B 4246 def +/uni283C 4247 def +/uni283D 4248 def +/uni283E 4249 def +/uni283F 4250 def +/uni2840 4251 def +/uni2841 4252 def +/uni2842 4253 def +/uni2843 4254 def +/uni2844 4255 def +/uni2845 4256 def +/uni2846 4257 def +/uni2847 4258 def +/uni2848 4259 def +/uni2849 4260 def +/uni284A 4261 def +/uni284B 4262 def +/uni284C 4263 def +/uni284D 4264 def +/uni284E 4265 def +/uni284F 4266 def +/uni2850 4267 def +/uni2851 4268 def +/uni2852 4269 def +/uni2853 4270 def +/uni2854 4271 def +/uni2855 4272 def +/uni2856 4273 def +/uni2857 4274 def +/uni2858 4275 def +/uni2859 4276 def +/uni285A 4277 def +/uni285B 4278 def +/uni285C 4279 def +/uni285D 4280 def +/uni285E 4281 def +/uni285F 4282 def +/uni2860 4283 def +/uni2861 4284 def +/uni2862 4285 def +/uni2863 4286 def +/uni2864 4287 def +/uni2865 4288 def +/uni2866 4289 def +/uni2867 4290 def +/uni2868 4291 def +/uni2869 4292 def +/uni286A 4293 def +/uni286B 4294 def +/uni286C 4295 def +/uni286D 4296 def +/uni286E 4297 def +/uni286F 4298 def +/uni2870 4299 def +/uni2871 4300 def +/uni2872 4301 def +/uni2873 4302 def +/uni2874 4303 def +/uni2875 4304 def +/uni2876 4305 def +/uni2877 4306 def +/uni2878 4307 def +/uni2879 4308 def +/uni287A 4309 def +/uni287B 4310 def +/uni287C 4311 def +/uni287D 4312 def +/uni287E 4313 def +/uni287F 4314 def +/uni2880 4315 def +/uni2881 4316 def +/uni2882 4317 def +/uni2883 4318 def +/uni2884 4319 def +/uni2885 4320 def +/uni2886 4321 def +/uni2887 4322 def +/uni2888 4323 def +/uni2889 4324 def +/uni288A 4325 def +/uni288B 4326 def +/uni288C 4327 def +/uni288D 4328 def +/uni288E 4329 def +/uni288F 4330 def +/uni2890 4331 def +/uni2891 4332 def +/uni2892 4333 def +/uni2893 4334 def +/uni2894 4335 def +/uni2895 4336 def +/uni2896 4337 def +/uni2897 4338 def +/uni2898 4339 def +/uni2899 4340 def +/uni289A 4341 def +/uni289B 4342 def +/uni289C 4343 def +/uni289D 4344 def +/uni289E 4345 def +/uni289F 4346 def +/uni28A0 4347 def +/uni28A1 4348 def +/uni28A2 4349 def +/uni28A3 4350 def +/uni28A4 4351 def +/uni28A5 4352 def +/uni28A6 4353 def +/uni28A7 4354 def +/uni28A8 4355 def +/uni28A9 4356 def +/uni28AA 4357 def +/uni28AB 4358 def +/uni28AC 4359 def +/uni28AD 4360 def +/uni28AE 4361 def +/uni28AF 4362 def +/uni28B0 4363 def +/uni28B1 4364 def +/uni28B2 4365 def +/uni28B3 4366 def +/uni28B4 4367 def +/uni28B5 4368 def +/uni28B6 4369 def +/uni28B7 4370 def +/uni28B8 4371 def +/uni28B9 4372 def +/uni28BA 4373 def +/uni28BB 4374 def +/uni28BC 4375 def +/uni28BD 4376 def +/uni28BE 4377 def +/uni28BF 4378 def +/uni28C0 4379 def +/uni28C1 4380 def +/uni28C2 4381 def +/uni28C3 4382 def +/uni28C4 4383 def +/uni28C5 4384 def +/uni28C6 4385 def +/uni28C7 4386 def +/uni28C8 4387 def +/uni28C9 4388 def +/uni28CA 4389 def +/uni28CB 4390 def +/uni28CC 4391 def +/uni28CD 4392 def +/uni28CE 4393 def +/uni28CF 4394 def +/uni28D0 4395 def +/uni28D1 4396 def +/uni28D2 4397 def +/uni28D3 4398 def +/uni28D4 4399 def +/uni28D5 4400 def +/uni28D6 4401 def +/uni28D7 4402 def +/uni28D8 4403 def +/uni28D9 4404 def +/uni28DA 4405 def +/uni28DB 4406 def +/uni28DC 4407 def +/uni28DD 4408 def +/uni28DE 4409 def +/uni28DF 4410 def +/uni28E0 4411 def +/uni28E1 4412 def +/uni28E2 4413 def +/uni28E3 4414 def +/uni28E4 4415 def +/uni28E5 4416 def +/uni28E6 4417 def +/uni28E7 4418 def +/uni28E8 4419 def +/uni28E9 4420 def +/uni28EA 4421 def +/uni28EB 4422 def +/uni28EC 4423 def +/uni28ED 4424 def +/uni28EE 4425 def +/uni28EF 4426 def +/uni28F0 4427 def +/uni28F1 4428 def +/uni28F2 4429 def +/uni28F3 4430 def +/uni28F4 4431 def +/uni28F5 4432 def +/uni28F6 4433 def +/uni28F7 4434 def +/uni28F8 4435 def +/uni28F9 4436 def +/uni28FA 4437 def +/uni28FB 4438 def +/uni28FC 4439 def +/uni28FD 4440 def +/uni28FE 4441 def +/uni28FF 4442 def +/uni2906 4443 def +/uni2907 4444 def +/uni290A 4445 def +/uni290B 4446 def +/uni2940 4447 def +/uni2941 4448 def +/uni2983 4449 def +/uni2984 4450 def +/uni29CE 4451 def +/uni29CF 4452 def +/uni29D0 4453 def +/uni29D1 4454 def +/uni29D2 4455 def +/uni29D3 4456 def +/uni29D4 4457 def +/uni29D5 4458 def +/uni29EB 4459 def +/uni29FA 4460 def +/uni29FB 4461 def +/uni2A00 4462 def +/uni2A01 4463 def +/uni2A02 4464 def +/uni2A0C 4465 def +/uni2A0D 4466 def +/uni2A0E 4467 def +/uni2A0F 4468 def +/uni2A10 4469 def +/uni2A11 4470 def +/uni2A12 4471 def +/uni2A13 4472 def +/uni2A14 4473 def +/uni2A15 4474 def +/uni2A16 4475 def +/uni2A17 4476 def +/uni2A18 4477 def +/uni2A19 4478 def +/uni2A1A 4479 def +/uni2A1B 4480 def +/uni2A1C 4481 def +/uni2A2F 4482 def +/uni2A6A 4483 def +/uni2A6B 4484 def +/uni2A7D 4485 def +/uni2A7E 4486 def +/uni2A7F 4487 def +/uni2A80 4488 def +/uni2A81 4489 def +/uni2A82 4490 def +/uni2A83 4491 def +/uni2A84 4492 def +/uni2A85 4493 def +/uni2A86 4494 def +/uni2A87 4495 def +/uni2A88 4496 def +/uni2A89 4497 def +/uni2A8A 4498 def +/uni2A8B 4499 def +/uni2A8C 4500 def +/uni2A8D 4501 def +/uni2A8E 4502 def +/uni2A8F 4503 def +/uni2A90 4504 def +/uni2A91 4505 def +/uni2A92 4506 def +/uni2A93 4507 def +/uni2A94 4508 def +/uni2A95 4509 def +/uni2A96 4510 def +/uni2A97 4511 def +/uni2A98 4512 def +/uni2A99 4513 def +/uni2A9A 4514 def +/uni2A9B 4515 def +/uni2A9C 4516 def +/uni2A9D 4517 def +/uni2A9E 4518 def +/uni2A9F 4519 def +/uni2AA0 4520 def +/uni2AAE 4521 def +/uni2AAF 4522 def +/uni2AB0 4523 def +/uni2AB1 4524 def +/uni2AB2 4525 def +/uni2AB3 4526 def +/uni2AB4 4527 def +/uni2AB5 4528 def +/uni2AB6 4529 def +/uni2AB7 4530 def +/uni2AB8 4531 def +/uni2AB9 4532 def +/uni2ABA 4533 def +/uni2AF9 4534 def +/uni2AFA 4535 def +/uni2B00 4536 def +/uni2B01 4537 def +/uni2B02 4538 def +/uni2B03 4539 def +/uni2B04 4540 def +/uni2B05 4541 def +/uni2B06 4542 def +/uni2B07 4543 def +/uni2B08 4544 def +/uni2B09 4545 def +/uni2B0A 4546 def +/uni2B0B 4547 def +/uni2B0C 4548 def +/uni2B0D 4549 def +/uni2B0E 4550 def +/uni2B0F 4551 def +/uni2B10 4552 def +/uni2B11 4553 def +/uni2B12 4554 def +/uni2B13 4555 def +/uni2B14 4556 def +/uni2B15 4557 def +/uni2B16 4558 def +/uni2B17 4559 def +/uni2B18 4560 def +/uni2B19 4561 def +/uni2B1A 4562 def +/uni2B1F 4563 def +/uni2B20 4564 def +/uni2B21 4565 def +/uni2B22 4566 def +/uni2B23 4567 def +/uni2B24 4568 def +/uni2B53 4569 def +/uni2B54 4570 def +/uni2C60 4571 def +/uni2C61 4572 def +/uni2C62 4573 def +/uni2C63 4574 def +/uni2C64 4575 def +/uni2C65 4576 def +/uni2C66 4577 def +/uni2C67 4578 def +/uni2C68 4579 def +/uni2C69 4580 def +/uni2C6A 4581 def +/uni2C6B 4582 def +/uni2C6C 4583 def +/uni2C6D 4584 def +/uni2C6E 4585 def +/uni2C6F 4586 def +/uni2C70 4587 def +/uni2C71 4588 def +/uni2C72 4589 def +/uni2C73 4590 def +/uni2C74 4591 def +/uni2C75 4592 def +/uni2C76 4593 def +/uni2C77 4594 def +/uni2C79 4595 def +/uni2C7A 4596 def +/uni2C7B 4597 def +/uni2C7C 4598 def +/uni2C7D 4599 def +/uni2C7E 4600 def +/uni2C7F 4601 def +/uni2D00 4602 def +/uni2D01 4603 def +/uni2D02 4604 def +/uni2D03 4605 def +/uni2D04 4606 def +/uni2D05 4607 def +/uni2D06 4608 def +/uni2D07 4609 def +/uni2D08 4610 def +/uni2D09 4611 def +/uni2D0A 4612 def +/uni2D0B 4613 def +/uni2D0C 4614 def +/uni2D0D 4615 def +/uni2D0E 4616 def +/uni2D0F 4617 def +/uni2D10 4618 def +/uni2D11 4619 def +/uni2D12 4620 def +/uni2D13 4621 def +/uni2D14 4622 def +/uni2D15 4623 def +/uni2D16 4624 def +/uni2D17 4625 def +/uni2D18 4626 def +/uni2D19 4627 def +/uni2D1A 4628 def +/uni2D1B 4629 def +/uni2D1C 4630 def +/uni2D1D 4631 def +/uni2D1E 4632 def +/uni2D1F 4633 def +/uni2D20 4634 def +/uni2D21 4635 def +/uni2D22 4636 def +/uni2D23 4637 def +/uni2D24 4638 def +/uni2D25 4639 def +/uni2D30 4640 def +/uni2D31 4641 def +/uni2D32 4642 def +/uni2D33 4643 def +/uni2D34 4644 def +/uni2D35 4645 def +/uni2D36 4646 def +/uni2D37 4647 def +/uni2D38 4648 def +/uni2D39 4649 def +/uni2D3A 4650 def +/uni2D3B 4651 def +/uni2D3C 4652 def +/uni2D3D 4653 def +/uni2D3E 4654 def +/uni2D3F 4655 def +/uni2D40 4656 def +/uni2D41 4657 def +/uni2D42 4658 def +/uni2D43 4659 def +/uni2D44 4660 def +/uni2D45 4661 def +/uni2D46 4662 def +/uni2D47 4663 def +/uni2D48 4664 def +/uni2D49 4665 def +/uni2D4A 4666 def +/uni2D4B 4667 def +/uni2D4C 4668 def +/uni2D4D 4669 def +/uni2D4E 4670 def +/uni2D4F 4671 def +/uni2D50 4672 def +/uni2D51 4673 def +/uni2D52 4674 def +/uni2D53 4675 def +/uni2D54 4676 def +/uni2D55 4677 def +/uni2D56 4678 def +/uni2D57 4679 def +/uni2D58 4680 def +/uni2D59 4681 def +/uni2D5A 4682 def +/uni2D5B 4683 def +/uni2D5C 4684 def +/uni2D5D 4685 def +/uni2D5E 4686 def +/uni2D5F 4687 def +/uni2D60 4688 def +/uni2D61 4689 def +/uni2D62 4690 def +/uni2D63 4691 def +/uni2D64 4692 def +/uni2D65 4693 def +/uni2D6F 4694 def +/uni2E18 4695 def +/uni2E1F 4696 def +/uni2E22 4697 def +/uni2E23 4698 def +/uni2E24 4699 def +/uni2E25 4700 def +/uni2E2E 4701 def +/uni4DC0 4702 def +/uni4DC1 4703 def +/uni4DC2 4704 def +/uni4DC3 4705 def +/uni4DC4 4706 def +/uni4DC5 4707 def +/uni4DC6 4708 def +/uni4DC7 4709 def +/uni4DC8 4710 def +/uni4DC9 4711 def +/uni4DCA 4712 def +/uni4DCB 4713 def +/uni4DCC 4714 def +/uni4DCD 4715 def +/uni4DCE 4716 def +/uni4DCF 4717 def +/uni4DD0 4718 def +/uni4DD1 4719 def +/uni4DD2 4720 def +/uni4DD3 4721 def +/uni4DD4 4722 def +/uni4DD5 4723 def +/uni4DD6 4724 def +/uni4DD7 4725 def +/uni4DD8 4726 def +/uni4DD9 4727 def +/uni4DDA 4728 def +/uni4DDB 4729 def +/uni4DDC 4730 def +/uni4DDD 4731 def +/uni4DDE 4732 def +/uni4DDF 4733 def +/uni4DE0 4734 def +/uni4DE1 4735 def +/uni4DE2 4736 def +/uni4DE3 4737 def +/uni4DE4 4738 def +/uni4DE5 4739 def +/uni4DE6 4740 def +/uni4DE7 4741 def +/uni4DE8 4742 def +/uni4DE9 4743 def +/uni4DEA 4744 def +/uni4DEB 4745 def +/uni4DEC 4746 def +/uni4DED 4747 def +/uni4DEE 4748 def +/uni4DEF 4749 def +/uni4DF0 4750 def +/uni4DF1 4751 def +/uni4DF2 4752 def +/uni4DF3 4753 def +/uni4DF4 4754 def +/uni4DF5 4755 def +/uni4DF6 4756 def +/uni4DF7 4757 def +/uni4DF8 4758 def +/uni4DF9 4759 def +/uni4DFA 4760 def +/uni4DFB 4761 def +/uni4DFC 4762 def +/uni4DFD 4763 def +/uni4DFE 4764 def +/uni4DFF 4765 def +/uniA4D0 4766 def +/uniA4D1 4767 def +/uniA4D2 4768 def +/uniA4D3 4769 def +/uniA4D4 4770 def +/uniA4D5 4771 def +/uniA4D6 4772 def +/uniA4D7 4773 def +/uniA4D8 4774 def +/uniA4D9 4775 def +/uniA4DA 4776 def +/uniA4DB 4777 def +/uniA4DC 4778 def +/uniA4DD 4779 def +/uniA4DE 4780 def +/uniA4DF 4781 def +/uniA4E0 4782 def +/uniA4E1 4783 def +/uniA4E2 4784 def +/uniA4E3 4785 def +/uniA4E4 4786 def +/uniA4E5 4787 def +/uniA4E6 4788 def +/uniA4E7 4789 def +/uniA4E8 4790 def +/uniA4E9 4791 def +/uniA4EA 4792 def +/uniA4EB 4793 def +/uniA4EC 4794 def +/uniA4ED 4795 def +/uniA4EE 4796 def +/uniA4EF 4797 def +/uniA4F0 4798 def +/uniA4F1 4799 def +/uniA4F2 4800 def +/uniA4F3 4801 def +/uniA4F4 4802 def +/uniA4F5 4803 def +/uniA4F6 4804 def +/uniA4F7 4805 def +/uniA4F8 4806 def +/uniA4F9 4807 def +/uniA4FA 4808 def +/uniA4FB 4809 def +/uniA4FC 4810 def +/uniA4FD 4811 def +/uniA4FE 4812 def +/uniA4FF 4813 def +/uniA644 4814 def +/uniA645 4815 def +/uniA646 4816 def +/uniA647 4817 def +/uniA64C 4818 def +/uniA64D 4819 def +/uniA650 4820 def +/uniA651 4821 def +/uniA654 4822 def +/uniA655 4823 def +/uniA656 4824 def +/uniA657 4825 def +/uniA662 4826 def +/uniA663 4827 def +/uniA664 4828 def +/uniA665 4829 def +/uniA666 4830 def +/uniA667 4831 def +/uniA668 4832 def +/uniA669 4833 def +/uniA66A 4834 def +/uniA66B 4835 def +/uniA66C 4836 def +/uniA66D 4837 def +/uniA66E 4838 def +/uniA68A 4839 def +/uniA68B 4840 def +/uniA68C 4841 def +/uniA68D 4842 def +/uniA694 4843 def +/uniA695 4844 def +/uniA708 4845 def +/uniA709 4846 def +/uniA70A 4847 def +/uniA70B 4848 def +/uniA70C 4849 def +/uniA70D 4850 def +/uniA70E 4851 def +/uniA70F 4852 def +/uniA710 4853 def +/uniA711 4854 def +/uniA712 4855 def +/uniA713 4856 def +/uniA714 4857 def +/uniA715 4858 def +/uniA716 4859 def +/uniA71B 4860 def +/uniA71C 4861 def +/uniA71D 4862 def +/uniA71E 4863 def +/uniA71F 4864 def +/uniA722 4865 def +/uniA723 4866 def +/uniA724 4867 def +/uniA725 4868 def +/uniA726 4869 def +/uniA727 4870 def +/uniA728 4871 def +/uniA729 4872 def +/uniA72A 4873 def +/uniA72B 4874 def +/uniA730 4875 def +/uniA731 4876 def +/uniA732 4877 def +/uniA733 4878 def +/uniA734 4879 def +/uniA735 4880 def +/uniA736 4881 def +/uniA737 4882 def +/uniA738 4883 def +/uniA739 4884 def +/uniA73A 4885 def +/uniA73B 4886 def +/uniA73C 4887 def +/uniA73D 4888 def +/uniA73E 4889 def +/uniA73F 4890 def +/uniA740 4891 def +/uniA741 4892 def +/uniA746 4893 def +/uniA747 4894 def +/uniA748 4895 def +/uniA749 4896 def +/uniA74A 4897 def +/uniA74B 4898 def +/uniA74E 4899 def +/uniA74F 4900 def +/uniA750 4901 def +/uniA751 4902 def +/uniA752 4903 def +/uniA753 4904 def +/uniA756 4905 def +/uniA757 4906 def +/uniA764 4907 def +/uniA765 4908 def +/uniA766 4909 def +/uniA767 4910 def +/uniA780 4911 def +/uniA781 4912 def +/uniA782 4913 def +/uniA783 4914 def +/uniA789 4915 def +/uniA78A 4916 def +/uniA78B 4917 def +/uniA78C 4918 def +/uniA78D 4919 def +/uniA78E 4920 def +/uniA790 4921 def +/uniA791 4922 def +/uniA7A0 4923 def +/uniA7A1 4924 def +/uniA7A2 4925 def +/uniA7A3 4926 def +/uniA7A4 4927 def +/uniA7A5 4928 def +/uniA7A6 4929 def +/uniA7A7 4930 def +/uniA7A8 4931 def +/uniA7A9 4932 def +/uniA7AA 4933 def +/uniA7F8 4934 def +/uniA7F9 4935 def +/uniA7FA 4936 def +/uniA7FB 4937 def +/uniA7FC 4938 def +/uniA7FD 4939 def +/uniA7FE 4940 def +/uniA7FF 4941 def +/uni02E5.5 4942 def +/uni02E6.5 4943 def +/uni02E7.5 4944 def +/uni02E8.5 4945 def +/uni02E9.5 4946 def +/uni02E5.4 4947 def +/uni02E6.4 4948 def +/uni02E7.4 4949 def +/uni02E8.4 4950 def +/uni02E9.4 4951 def +/uni02E5.3 4952 def +/uni02E6.3 4953 def +/uni02E7.3 4954 def +/uni02E8.3 4955 def +/uni02E9.3 4956 def +/uni02E5.2 4957 def +/uni02E6.2 4958 def +/uni02E7.2 4959 def +/uni02E8.2 4960 def +/uni02E9.2 4961 def +/uni02E5.1 4962 def +/uni02E6.1 4963 def +/uni02E7.1 4964 def +/uni02E8.1 4965 def +/uni02E9.1 4966 def +/stem 4967 def +/uniF000 4968 def +/uniF001 4969 def +/uniF002 4970 def +/uniF003 4971 def +/uniF400 4972 def +/uniF401 4973 def +/uniF402 4974 def +/uniF403 4975 def +/uniF404 4976 def +/uniF405 4977 def +/uniF406 4978 def +/uniF407 4979 def +/uniF408 4980 def +/uniF409 4981 def +/uniF40A 4982 def +/uniF40B 4983 def +/uniF40C 4984 def +/uniF40D 4985 def +/uniF40E 4986 def +/uniF40F 4987 def +/uniF410 4988 def +/uniF411 4989 def +/uniF412 4990 def +/uniF413 4991 def +/uniF414 4992 def +/uniF415 4993 def +/uniF416 4994 def +/uniF417 4995 def +/uniF418 4996 def +/uniF419 4997 def +/uniF41A 4998 def +/uniF41B 4999 def +/uniF41C 5000 def +/uniF41D 5001 def +/uniF41E 5002 def +/uniF41F 5003 def +/uniF420 5004 def +/uniF421 5005 def +/uniF422 5006 def +/uniF423 5007 def +/uniF424 5008 def +/uniF425 5009 def +/uniF426 5010 def +/uniF428 5011 def +/uniF429 5012 def +/uniF42A 5013 def +/uniF42B 5014 def +/uniF42C 5015 def +/uniF42D 5016 def +/uniF42E 5017 def +/uniF42F 5018 def +/uniF430 5019 def +/uniF431 5020 def +/uniF432 5021 def +/uniF433 5022 def +/uniF434 5023 def +/uniF435 5024 def +/uniF436 5025 def +/uniF437 5026 def +/uniF438 5027 def +/uniF439 5028 def +/uniF43A 5029 def +/uniF43B 5030 def +/uniF43C 5031 def +/uniF43D 5032 def +/uniF43E 5033 def +/uniF43F 5034 def +/uniF440 5035 def +/uniF441 5036 def +/uniF6C5 5037 def +/uniFB00 5038 def +/fi 5039 def +/fl 5040 def +/uniFB03 5041 def +/uniFB04 5042 def +/uniFB05 5043 def +/uniFB06 5044 def +/uniFB13 5045 def +/uniFB14 5046 def +/uniFB15 5047 def +/uniFB16 5048 def +/uniFB17 5049 def +/uniFB1D 5050 def +/uniFB1E 5051 def +/uniFB1F 5052 def +/uniFB20 5053 def +/uniFB21 5054 def +/uniFB22 5055 def +/uniFB23 5056 def +/uniFB24 5057 def +/uniFB25 5058 def +/uniFB26 5059 def +/uniFB27 5060 def +/uniFB28 5061 def +/uniFB29 5062 def +/uniFB2A 5063 def +/uniFB2B 5064 def +/uniFB2C 5065 def +/uniFB2D 5066 def +/uniFB2E 5067 def +/uniFB2F 5068 def +/uniFB30 5069 def +/uniFB31 5070 def +/uniFB32 5071 def +/uniFB33 5072 def +/uniFB34 5073 def +/uniFB35 5074 def +/uniFB36 5075 def +/uniFB38 5076 def +/uniFB39 5077 def +/uniFB3A 5078 def +/uniFB3B 5079 def +/uniFB3C 5080 def +/uniFB3E 5081 def +/uniFB40 5082 def +/uniFB41 5083 def +/uniFB43 5084 def +/uniFB44 5085 def +/uniFB46 5086 def +/uniFB47 5087 def +/uniFB48 5088 def +/uniFB49 5089 def +/uniFB4A 5090 def +/uniFB4B 5091 def +/uniFB4C 5092 def +/uniFB4D 5093 def +/uniFB4E 5094 def +/uniFB4F 5095 def +/uniFB52 5096 def +/uniFB53 5097 def +/uniFB54 5098 def +/uniFB55 5099 def +/uniFB56 5100 def +/uniFB57 5101 def +/uniFB58 5102 def +/uniFB59 5103 def +/uniFB5A 5104 def +/uniFB5B 5105 def +/uniFB5C 5106 def +/uniFB5D 5107 def +/uniFB5E 5108 def +/uniFB5F 5109 def +/uniFB60 5110 def +/uniFB61 5111 def +/uniFB62 5112 def +/uniFB63 5113 def +/uniFB64 5114 def +/uniFB65 5115 def +/uniFB66 5116 def +/uniFB67 5117 def +/uniFB68 5118 def +/uniFB69 5119 def +/uniFB6A 5120 def +/uniFB6B 5121 def +/uniFB6C 5122 def +/uniFB6D 5123 def +/uniFB6E 5124 def +/uniFB6F 5125 def +/uniFB70 5126 def +/uniFB71 5127 def +/uniFB72 5128 def +/uniFB73 5129 def +/uniFB74 5130 def +/uniFB75 5131 def +/uniFB76 5132 def +/uniFB77 5133 def +/uniFB78 5134 def +/uniFB79 5135 def +/uniFB7A 5136 def +/uniFB7B 5137 def +/uniFB7C 5138 def +/uniFB7D 5139 def +/uniFB7E 5140 def +/uniFB7F 5141 def +/uniFB80 5142 def +/uniFB81 5143 def +/uniFB82 5144 def +/uniFB83 5145 def +/uniFB84 5146 def +/uniFB85 5147 def +/uniFB86 5148 def +/uniFB87 5149 def +/uniFB88 5150 def +/uniFB89 5151 def +/uniFB8A 5152 def +/uniFB8B 5153 def +/uniFB8C 5154 def +/uniFB8D 5155 def +/uniFB8E 5156 def +/uniFB8F 5157 def +/uniFB90 5158 def +/uniFB91 5159 def +/uniFB92 5160 def +/uniFB93 5161 def +/uniFB94 5162 def +/uniFB95 5163 def +/uniFB96 5164 def +/uniFB97 5165 def +/uniFB98 5166 def +/uniFB99 5167 def +/uniFB9A 5168 def +/uniFB9B 5169 def +/uniFB9C 5170 def +/uniFB9D 5171 def +/uniFB9E 5172 def +/uniFB9F 5173 def +/uniFBA0 5174 def +/uniFBA1 5175 def +/uniFBA2 5176 def +/uniFBA3 5177 def +/uniFBAA 5178 def +/uniFBAB 5179 def +/uniFBAC 5180 def +/uniFBAD 5181 def +/uniFBD3 5182 def +/uniFBD4 5183 def +/uniFBD5 5184 def +/uniFBD6 5185 def +/uniFBD7 5186 def +/uniFBD8 5187 def +/uniFBD9 5188 def +/uniFBDA 5189 def +/uniFBDB 5190 def +/uniFBDC 5191 def +/uniFBDE 5192 def +/uniFBDF 5193 def +/uniFBE4 5194 def +/uniFBE5 5195 def +/uniFBE6 5196 def +/uniFBE7 5197 def +/uniFBE8 5198 def +/uniFBE9 5199 def +/uniFBFC 5200 def +/uniFBFD 5201 def +/uniFBFE 5202 def +/uniFBFF 5203 def +/uniFE00 5204 def +/uniFE01 5205 def +/uniFE02 5206 def +/uniFE03 5207 def +/uniFE04 5208 def +/uniFE05 5209 def +/uniFE06 5210 def +/uniFE07 5211 def +/uniFE08 5212 def +/uniFE09 5213 def +/uniFE0A 5214 def +/uniFE0B 5215 def +/uniFE0C 5216 def +/uniFE0D 5217 def +/uniFE0E 5218 def +/uniFE0F 5219 def +/uniFE20 5220 def +/uniFE21 5221 def +/uniFE22 5222 def +/uniFE23 5223 def +/uniFE70 5224 def +/uniFE71 5225 def +/uniFE72 5226 def +/uniFE73 5227 def +/uniFE74 5228 def +/uniFE76 5229 def +/uniFE77 5230 def +/uniFE78 5231 def +/uniFE79 5232 def +/uniFE7A 5233 def +/uniFE7B 5234 def +/uniFE7C 5235 def +/uniFE7D 5236 def +/uniFE7E 5237 def +/uniFE7F 5238 def +/uniFE80 5239 def +/uniFE81 5240 def +/uniFE82 5241 def +/uniFE83 5242 def +/uniFE84 5243 def +/uniFE85 5244 def +/uniFE86 5245 def +/uniFE87 5246 def +/uniFE88 5247 def +/uniFE89 5248 def +/uniFE8A 5249 def +/uniFE8B 5250 def +/uniFE8C 5251 def +/uniFE8D 5252 def +/uniFE8E 5253 def +/uniFE8F 5254 def +/uniFE90 5255 def +/uniFE91 5256 def +/uniFE92 5257 def +/uniFE93 5258 def +/uniFE94 5259 def +/uniFE95 5260 def +/uniFE96 5261 def +/uniFE97 5262 def +/uniFE98 5263 def +/uniFE99 5264 def +/uniFE9A 5265 def +/uniFE9B 5266 def +/uniFE9C 5267 def +/uniFE9D 5268 def +/uniFE9E 5269 def +/uniFE9F 5270 def +/uniFEA0 5271 def +/uniFEA1 5272 def +/uniFEA2 5273 def +/uniFEA3 5274 def +/uniFEA4 5275 def +/uniFEA5 5276 def +/uniFEA6 5277 def +/uniFEA7 5278 def +/uniFEA8 5279 def +/uniFEA9 5280 def +/uniFEAA 5281 def +/uniFEAB 5282 def +/uniFEAC 5283 def +/uniFEAD 5284 def +/uniFEAE 5285 def +/uniFEAF 5286 def +/uniFEB0 5287 def +/uniFEB1 5288 def +/uniFEB2 5289 def +/uniFEB3 5290 def +/uniFEB4 5291 def +/uniFEB5 5292 def +/uniFEB6 5293 def +/uniFEB7 5294 def +/uniFEB8 5295 def +/uniFEB9 5296 def +/uniFEBA 5297 def +/uniFEBB 5298 def +/uniFEBC 5299 def +/uniFEBD 5300 def +/uniFEBE 5301 def +/uniFEBF 5302 def +/uniFEC0 5303 def +/uniFEC1 5304 def +/uniFEC2 5305 def +/uniFEC3 5306 def +/uniFEC4 5307 def +/uniFEC5 5308 def +/uniFEC6 5309 def +/uniFEC7 5310 def +/uniFEC8 5311 def +/uniFEC9 5312 def +/uniFECA 5313 def +/uniFECB 5314 def +/uniFECC 5315 def +/uniFECD 5316 def +/uniFECE 5317 def +/uniFECF 5318 def +/uniFED0 5319 def +/uniFED1 5320 def +/uniFED2 5321 def +/uniFED3 5322 def +/uniFED4 5323 def +/uniFED5 5324 def +/uniFED6 5325 def +/uniFED7 5326 def +/uniFED8 5327 def +/uniFED9 5328 def +/uniFEDA 5329 def +/uniFEDB 5330 def +/uniFEDC 5331 def +/uniFEDD 5332 def +/uniFEDE 5333 def +/uniFEDF 5334 def +/uniFEE0 5335 def +/uniFEE1 5336 def +/uniFEE2 5337 def +/uniFEE3 5338 def +/uniFEE4 5339 def +/uniFEE5 5340 def +/uniFEE6 5341 def +/uniFEE7 5342 def +/uniFEE8 5343 def +/uniFEE9 5344 def +/uniFEEA 5345 def +/uniFEEB 5346 def +/uniFEEC 5347 def +/uniFEED 5348 def +/uniFEEE 5349 def +/uniFEEF 5350 def +/uniFEF0 5351 def +/uniFEF1 5352 def +/uniFEF2 5353 def +/uniFEF3 5354 def +/uniFEF4 5355 def +/uniFEF5 5356 def +/uniFEF6 5357 def +/uniFEF7 5358 def +/uniFEF8 5359 def +/uniFEF9 5360 def +/uniFEFA 5361 def +/uniFEFB 5362 def +/uniFEFC 5363 def +/uniFEFF 5364 def +/uniFFF9 5365 def +/uniFFFA 5366 def +/uniFFFB 5367 def +/uniFFFC 5368 def +/uniFFFD 5369 def +/u10300 5370 def +/u10301 5371 def +/u10302 5372 def +/u10303 5373 def +/u10304 5374 def +/u10305 5375 def +/u10306 5376 def +/u10307 5377 def +/u10308 5378 def +/u10309 5379 def +/u1030A 5380 def +/u1030B 5381 def +/u1030C 5382 def +/u1030D 5383 def +/u1030E 5384 def +/u1030F 5385 def +/u10310 5386 def +/u10311 5387 def +/u10312 5388 def +/u10313 5389 def +/u10314 5390 def +/u10315 5391 def +/u10316 5392 def +/u10317 5393 def +/u10318 5394 def +/u10319 5395 def +/u1031A 5396 def +/u1031B 5397 def +/u1031C 5398 def +/u1031D 5399 def +/u1031E 5400 def +/u10320 5401 def +/u10321 5402 def +/u10322 5403 def +/u10323 5404 def +/u1D300 5405 def +/u1D301 5406 def +/u1D302 5407 def +/u1D303 5408 def +/u1D304 5409 def +/u1D305 5410 def +/u1D306 5411 def +/u1D307 5412 def +/u1D308 5413 def +/u1D309 5414 def +/u1D30A 5415 def +/u1D30B 5416 def +/u1D30C 5417 def +/u1D30D 5418 def +/u1D30E 5419 def +/u1D30F 5420 def +/u1D310 5421 def +/u1D311 5422 def +/u1D312 5423 def +/u1D313 5424 def +/u1D314 5425 def +/u1D315 5426 def +/u1D316 5427 def +/u1D317 5428 def +/u1D318 5429 def +/u1D319 5430 def +/u1D31A 5431 def +/u1D31B 5432 def +/u1D31C 5433 def +/u1D31D 5434 def +/u1D31E 5435 def +/u1D31F 5436 def +/u1D320 5437 def +/u1D321 5438 def +/u1D322 5439 def +/u1D323 5440 def +/u1D324 5441 def +/u1D325 5442 def +/u1D326 5443 def +/u1D327 5444 def +/u1D328 5445 def +/u1D329 5446 def +/u1D32A 5447 def +/u1D32B 5448 def +/u1D32C 5449 def +/u1D32D 5450 def +/u1D32E 5451 def +/u1D32F 5452 def +/u1D330 5453 def +/u1D331 5454 def +/u1D332 5455 def +/u1D333 5456 def +/u1D334 5457 def +/u1D335 5458 def +/u1D336 5459 def +/u1D337 5460 def +/u1D338 5461 def +/u1D339 5462 def +/u1D33A 5463 def +/u1D33B 5464 def +/u1D33C 5465 def +/u1D33D 5466 def +/u1D33E 5467 def +/u1D33F 5468 def +/u1D340 5469 def +/u1D341 5470 def +/u1D342 5471 def +/u1D343 5472 def +/u1D344 5473 def +/u1D345 5474 def +/u1D346 5475 def +/u1D347 5476 def +/u1D348 5477 def +/u1D349 5478 def +/u1D34A 5479 def +/u1D34B 5480 def +/u1D34C 5481 def +/u1D34D 5482 def +/u1D34E 5483 def +/u1D34F 5484 def +/u1D350 5485 def +/u1D351 5486 def +/u1D352 5487 def +/u1D353 5488 def +/u1D354 5489 def +/u1D355 5490 def +/u1D356 5491 def +/u1D538 5492 def +/u1D539 5493 def +/u1D53B 5494 def +/u1D53C 5495 def +/u1D53D 5496 def +/u1D53E 5497 def +/u1D540 5498 def +/u1D541 5499 def +/u1D542 5500 def +/u1D543 5501 def +/u1D544 5502 def +/u1D546 5503 def +/u1D54A 5504 def +/u1D54B 5505 def +/u1D54C 5506 def +/u1D54D 5507 def +/u1D54E 5508 def +/u1D54F 5509 def +/u1D550 5510 def +/u1D552 5511 def +/u1D553 5512 def +/u1D554 5513 def +/u1D555 5514 def +/u1D556 5515 def +/u1D557 5516 def +/u1D558 5517 def +/u1D559 5518 def +/u1D55A 5519 def +/u1D55B 5520 def +/u1D55C 5521 def +/u1D55D 5522 def +/u1D55E 5523 def +/u1D55F 5524 def +/u1D560 5525 def +/u1D561 5526 def +/u1D562 5527 def +/u1D563 5528 def +/u1D564 5529 def +/u1D565 5530 def +/u1D566 5531 def +/u1D567 5532 def +/u1D568 5533 def +/u1D569 5534 def +/u1D56A 5535 def +/u1D56B 5536 def +/u1D5A0 5537 def +/u1D5A1 5538 def +/u1D5A2 5539 def +/u1D5A3 5540 def +/u1D5A4 5541 def +/u1D5A5 5542 def +/u1D5A6 5543 def +/u1D5A7 5544 def +/u1D5A8 5545 def +/u1D5A9 5546 def +/u1D5AA 5547 def +/u1D5AB 5548 def +/u1D5AC 5549 def +/u1D5AD 5550 def +/u1D5AE 5551 def +/u1D5AF 5552 def +/u1D5B0 5553 def +/u1D5B1 5554 def +/u1D5B2 5555 def +/u1D5B3 5556 def +/u1D5B4 5557 def +/u1D5B5 5558 def +/u1D5B6 5559 def +/u1D5B7 5560 def +/u1D5B8 5561 def +/u1D5B9 5562 def +/u1D5BA 5563 def +/u1D5BB 5564 def +/u1D5BC 5565 def +/u1D5BD 5566 def +/u1D5BE 5567 def +/u1D5BF 5568 def +/u1D5C0 5569 def +/u1D5C1 5570 def +/u1D5C2 5571 def +/u1D5C3 5572 def +/u1D5C4 5573 def +/u1D5C5 5574 def +/u1D5C6 5575 def +/u1D5C7 5576 def +/u1D5C8 5577 def +/u1D5C9 5578 def +/u1D5CA 5579 def +/u1D5CB 5580 def +/u1D5CC 5581 def +/u1D5CD 5582 def +/u1D5CE 5583 def +/u1D5CF 5584 def +/u1D5D0 5585 def +/u1D5D1 5586 def +/u1D5D2 5587 def +/u1D5D3 5588 def +/u1D7D8 5589 def +/u1D7D9 5590 def +/u1D7DA 5591 def +/u1D7DB 5592 def +/u1D7DC 5593 def +/u1D7DD 5594 def +/u1D7DE 5595 def +/u1D7DF 5596 def +/u1D7E0 5597 def +/u1D7E1 5598 def +/u1D7E2 5599 def +/u1D7E3 5600 def +/u1D7E4 5601 def +/u1D7E5 5602 def +/u1D7E6 5603 def +/u1D7E7 5604 def +/u1D7E8 5605 def +/u1D7E9 5606 def +/u1D7EA 5607 def +/u1D7EB 5608 def +/u1EE00 5609 def +/u1EE01 5610 def +/u1EE02 5611 def +/u1EE03 5612 def +/u1EE05 5613 def +/u1EE06 5614 def +/u1EE07 5615 def +/u1EE08 5616 def +/u1EE09 5617 def +/u1EE0A 5618 def +/u1EE0B 5619 def +/u1EE0C 5620 def +/u1EE0D 5621 def +/u1EE0E 5622 def +/u1EE0F 5623 def +/u1EE10 5624 def +/u1EE11 5625 def +/u1EE12 5626 def +/u1EE13 5627 def +/u1EE14 5628 def +/u1EE15 5629 def +/u1EE16 5630 def +/u1EE17 5631 def +/u1EE18 5632 def +/u1EE19 5633 def +/u1EE1A 5634 def +/u1EE1B 5635 def +/u1EE1C 5636 def +/u1EE1D 5637 def +/u1EE1E 5638 def +/u1EE1F 5639 def +/u1EE21 5640 def +/u1EE22 5641 def +/u1EE24 5642 def +/u1EE27 5643 def +/u1EE29 5644 def +/u1EE2A 5645 def +/u1EE2B 5646 def +/u1EE2C 5647 def +/u1EE2D 5648 def +/u1EE2E 5649 def +/u1EE2F 5650 def +/u1EE30 5651 def +/u1EE31 5652 def +/u1EE32 5653 def +/u1EE34 5654 def +/u1EE35 5655 def +/u1EE36 5656 def +/u1EE37 5657 def +/u1EE39 5658 def +/u1EE3B 5659 def +/u1EE61 5660 def +/u1EE62 5661 def +/u1EE64 5662 def +/u1EE67 5663 def +/u1EE68 5664 def +/u1EE69 5665 def +/u1EE6A 5666 def +/u1EE6C 5667 def +/u1EE6D 5668 def +/u1EE6E 5669 def +/u1EE6F 5670 def +/u1EE70 5671 def +/u1EE71 5672 def +/u1EE72 5673 def +/u1EE74 5674 def +/u1EE75 5675 def +/u1EE76 5676 def +/u1EE77 5677 def +/u1EE79 5678 def +/u1EE7A 5679 def +/u1EE7B 5680 def +/u1EE7C 5681 def +/u1EE7E 5682 def +/u1F030 5683 def +/u1F031 5684 def +/u1F032 5685 def +/u1F033 5686 def +/u1F034 5687 def +/u1F035 5688 def +/u1F036 5689 def +/u1F037 5690 def +/u1F038 5691 def +/u1F039 5692 def +/u1F03A 5693 def +/u1F03B 5694 def +/u1F03C 5695 def +/u1F03D 5696 def +/u1F03E 5697 def +/u1F03F 5698 def +/u1F040 5699 def +/u1F041 5700 def +/u1F042 5701 def +/u1F043 5702 def +/u1F044 5703 def +/u1F045 5704 def +/u1F046 5705 def +/u1F047 5706 def +/u1F048 5707 def +/u1F049 5708 def +/u1F04A 5709 def +/u1F04B 5710 def +/u1F04C 5711 def +/u1F04D 5712 def +/u1F04E 5713 def +/u1F04F 5714 def +/u1F050 5715 def +/u1F051 5716 def +/u1F052 5717 def +/u1F053 5718 def +/u1F054 5719 def +/u1F055 5720 def +/u1F056 5721 def +/u1F057 5722 def +/u1F058 5723 def +/u1F059 5724 def +/u1F05A 5725 def +/u1F05B 5726 def +/u1F05C 5727 def +/u1F05D 5728 def +/u1F05E 5729 def +/u1F05F 5730 def +/u1F060 5731 def +/u1F061 5732 def +/u1F062 5733 def +/u1F063 5734 def +/u1F064 5735 def +/u1F065 5736 def +/u1F066 5737 def +/u1F067 5738 def +/u1F068 5739 def +/u1F069 5740 def +/u1F06A 5741 def +/u1F06B 5742 def +/u1F06C 5743 def +/u1F06D 5744 def +/u1F06E 5745 def +/u1F06F 5746 def +/u1F070 5747 def +/u1F071 5748 def +/u1F072 5749 def +/u1F073 5750 def +/u1F074 5751 def +/u1F075 5752 def +/u1F076 5753 def +/u1F077 5754 def +/u1F078 5755 def +/u1F079 5756 def +/u1F07A 5757 def +/u1F07B 5758 def +/u1F07C 5759 def +/u1F07D 5760 def +/u1F07E 5761 def +/u1F07F 5762 def +/u1F080 5763 def +/u1F081 5764 def +/u1F082 5765 def +/u1F083 5766 def +/u1F084 5767 def +/u1F085 5768 def +/u1F086 5769 def +/u1F087 5770 def +/u1F088 5771 def +/u1F089 5772 def +/u1F08A 5773 def +/u1F08B 5774 def +/u1F08C 5775 def +/u1F08D 5776 def +/u1F08E 5777 def +/u1F08F 5778 def +/u1F090 5779 def +/u1F091 5780 def +/u1F092 5781 def +/u1F093 5782 def +/u1F0A0 5783 def +/u1F0A1 5784 def +/u1F0A2 5785 def +/u1F0A3 5786 def +/u1F0A4 5787 def +/u1F0A5 5788 def +/u1F0A6 5789 def +/u1F0A7 5790 def +/u1F0A8 5791 def +/u1F0A9 5792 def +/u1F0AA 5793 def +/u1F0AB 5794 def +/u1F0AC 5795 def +/u1F0AD 5796 def +/u1F0AE 5797 def +/u1F0B1 5798 def +/u1F0B2 5799 def +/u1F0B3 5800 def +/u1F0B4 5801 def +/u1F0B5 5802 def +/u1F0B6 5803 def +/u1F0B7 5804 def +/u1F0B8 5805 def +/u1F0B9 5806 def +/u1F0BA 5807 def +/u1F0BB 5808 def +/u1F0BC 5809 def +/u1F0BD 5810 def +/u1F0BE 5811 def +/u1F0C1 5812 def +/u1F0C2 5813 def +/u1F0C3 5814 def +/u1F0C4 5815 def +/u1F0C5 5816 def +/u1F0C6 5817 def +/u1F0C7 5818 def +/u1F0C8 5819 def +/u1F0C9 5820 def +/u1F0CA 5821 def +/u1F0CB 5822 def +/u1F0CC 5823 def +/u1F0CD 5824 def +/u1F0CE 5825 def +/u1F0CF 5826 def +/u1F0D1 5827 def +/u1F0D2 5828 def +/u1F0D3 5829 def +/u1F0D4 5830 def +/u1F0D5 5831 def +/u1F0D6 5832 def +/u1F0D7 5833 def +/u1F0D8 5834 def +/u1F0D9 5835 def +/u1F0DA 5836 def +/u1F0DB 5837 def +/u1F0DC 5838 def +/u1F0DD 5839 def +/u1F0DE 5840 def +/u1F0DF 5841 def +/u1F42D 5842 def +/u1F42E 5843 def +/u1F431 5844 def +/u1F435 5845 def +/u1F600 5846 def +/u1F601 5847 def +/u1F602 5848 def +/u1F603 5849 def +/u1F604 5850 def +/u1F605 5851 def +/u1F606 5852 def +/u1F607 5853 def +/u1F608 5854 def +/u1F609 5855 def +/u1F60A 5856 def +/u1F60B 5857 def +/u1F60C 5858 def +/u1F60D 5859 def +/u1F60E 5860 def +/u1F60F 5861 def +end readonly def + /sfnts[<0001000000120100000400204744454616f816dc0000012c0000001c47504f5344764c7500000148000000204753 +554227a43fc300000168000000964d415448093f338400000200000000f64f532f3269d8710a000002f800000056636d6170 +0013034000000350000000306376742000691d3900000380000001fe6670676d7134766a00000580000000ab676173700007 +00070000062c0000000c676c79663771325a0000063800000fb268656164085dc286000015ec00000036686865610d9f1e47 +0000162400000024686d7478305c06a40000164800005b806c6f636124d020ea000071c800002dce6d6178701b5306710000 +9f98000000206e616d6527ed3dbc00009fb8000001d4706f7374ad1958a00000a18c0000dcae707265703b07f10000017e3c +0000056800010000000c0000000000000002000200030003000116d616e5000100010000000a001c001e000144464c540008 +000400000000ffff00000000000000010000000a00920094001444464c54007a61726162008461726d6e0084627261690084 +63616e7300846368657200846379726c008467656f7200846772656b008468616e6900846865627200846b616e6100846c61 +6f2000846c61746e00846d61746800846e6b6f2000846f67616d008472756e72008474666e67008474686169008400040000 +0000ffff00000000000000000000000000010000000a00e000e80050003c0c0007dd00000000028200000460000005d50000 +0000000004600000000000000000000000000000046000000000000001680000046000000055000000000000000000000000 +00000000000000000000000000000000000000000000010e0000027600000000000000000000000000000000000000000000 +000000000000000000000000005a0000010e0000005a0000005a0000010e00000000000000000000010e0000005a0000005a +0000010e0000005a0000005a0000005a000001720000005a0000005a000002380000fb8f0000003c00000000000000000028 +000a000a000000000001000000000001040e019000050000053305990000011e05330599000003d7006602120000020b0603 +03080402020400000000020000000000000000000000506645640040ffffffff0614fe14019a076d01e30000000100000000 +0000000000020000000a000000140003000a00000014000c00000000001c00000000000000010001f6000001f60f000016d6 +013500b800cb00cb00c100aa009c01a600b800660000007100cb00a002b20085007500b800c301cb0189022d00cb00a600f0 +00d300aa008700cb03aa0400014a003300cb000000d9050200f4015400b4009c01390114013907060400044e04b4045204b8 +04e704cd0037047304cd04600473013303a2055605a60556053903c5021200c9001f00b801df007300ba03e9033303bc0444 +040e00df03cd03aa00e503aa0404000000cb008f00a4007b00b80014016f007f027b0252008f00c705cd009a009a006f00cb +00cd019e01d300f000ba018300d5009803040248009e01d500c100cb00f600830354027f00000333026600d300c700a400cd +008f009a0073040005d5010a00fe022b00a400b4009c00000062009c0000001d032d05d505d505d505f0007f007b005400a4 +06b80614072301d300b800cb00a601c301ec069300a000d3035c037103db0185042304a80448008f0139011401390360008f +05d5019a0614072306660179046004600460047b009c00000277046001aa00e904600762007b00c5007f027b000000b40252 +05cd006600bc00660077061000cd013b01850389008f007b0000001d00cd074a042f009c009c0000077d006f0000006f0335 +006a006f007b00ae00b2002d0396008f027b00f600830354063705f6008f009c04e10266008f018d02f600cd034400290066 +04ee00730000140000960000b707060504030201002c2010b002254964b040515820c859212d2cb002254964b040515820c8 +59212d2c20100720b00050b00d7920b8ffff5058041b0559b0051cb0032508b0042523e120b00050b00d7920b8ffff505804 +1b0559b0051cb0032508e12d2c4b505820b0fd454459212d2cb002254560442d2c4b5358b00225b0022545445921212d2c45 +442d2cb00225b0022549b00525b005254960b0206368208a108a233a8a10653a2d000000000200080002ffff0003000900aa +ff6a07ad066e000b00160022002e00340039003e004200460000013436333216151406232226253436321615140623222605 +1000212000111000212000031000212000111000212000012110002000053637112303112311162536372305352316028251 +3b3a52523a3b510242527453533a3b51fc6d01bf013c013d01bdfe43fec3fec4fe4187020e01740175020cfdf4fe8bfe8cfd +f2011404dbfe95fdfcfe9402b2584ca488a44c020c481c64fd20651c03ff3b51513b3a53533a3b51513b3a5353dbfec4fe43 +01bd013c013d01c0fe40fec30175020ffdf1fe8bfe8cfdf4020c016afefefe96016adf0b2a0125fea6015afedb2a995264b8 +b866000900aaff6a07ad066e000b00170023002f0035003a003f004300470000011000212000111000212000031000212000 +1110002120000134363216152334262206152134363216152334262206150721100020000536371123031123111625363723 +05352316013101bf013c013d01bdfe43fec3fec4fe4187020e01740175020cfdf4fe8bfe8cfdf203bc8cc48c873d543dfd29 +8cc48c873d543ddf04dbfe95fdfcfe9402b2584ca488a44c020c481c64fd20651c02eafec4fe4301bd013c013d01c0fe40fe +c30175020ffdf1fe8bfe8cfdf4020c02168bc5c58b537777538bc5c58b53777753acfefefe96016adf0b2a0125fea6015afe +db2a995264b8b8660009005fff6a08f9066e00030007000c001100170023002f0059007e0000013523160536372301112311 +1617363711232521100020001334363216152334262206152134363216152334262206150510002120001114071716171615 +14062227262f010207002120012603070607062226353437363f012637100021200011342706232227262f01171617262726 +2120070607363f0107060706222706033c651c0329481c64fe4ca44ce0584ca4fd4e04dbfe95fdfcfe94588cc48c873d543d +01c98cc48c873d543dfbbd020e01740175020c025d3b181e364c1f19120b2ad1fefafe8bfe8cfef9d12b0a12191f4c361e17 +3c5c028701bf013c013d01bd011b25261f19122d8829182f9adefec2fec4e09a2f1829882d12191f4c1b0101a1b866505264 +fea6015afedb2a0b0b2a012587fefefe96016a01ae8bc5c58b537777538bc5c58b53777753a20175020ffdf1fe8b1d1b1f14 +181f2526361f193920fee9d1fefa0106d001161e39191f3626251f19131e1c1dfec4fe4301bd013c14131a1f1939882d0e0f +c79ae0e09bc6100d2d8839191f1b1400000600aaff6a07ad066e000b00160022002e0034003c000001343633321615140623 +2226253436321615140623222605100021200011100021200013100021200011100021200013211000200025211617162437 +360282513b3a52523a3b510242527453533a3b51fbe6020e01740175020cfdf4fe8bfe8cfdf28701bf013c013d01bdfe43fe +c3fec4fe418d04dbfe95fdfcfe940442fc57215c8e01948e5c03ff3b51513b3a53533a3b51513b3a5353db0175020ffdf1fe +8bfe8cfdf4020c0174fec4fe4301bd013c013d01c0fe40feb9fefefe96016a7b755c8e018e5c000600aaff6a07ad066e000b +00170023002f0035003e00000134363216152334262206152134363216152334262206150510002120001110002120001310 +0021200011100021200013211000200025211617163732373602168cc48c873d543d01c98cc48c873d543dfbbd020e017401 +75020cfdf4fe8bfe8cfdf28701bf013c013d01bdfe43fec3fec4fe418d04dbfe95fdfcfe940442fc57215c8ecaca8e5c038c +8bc5c58b537777538bc5c58b53777753a20175020ffdf1fe8bfe8cfdf4020c0174fec4fe4301bd013c013d01c0fe40feb9fe +fefe96016a7b755c8e018e5c000700aaff6a07ad066e000b00170023002f003b0041004a0000011716070607062226353437 +0534363216152334262206152134363216152334262206150510002120001110002120001310002120001110002120001321 +1000200025211617163732373606a8411c01011a1b4c361bfbaf8cc48c873d543d01c98cc48c873d543dfbbd020e01740175 +020cfdf4fe8bfe8cfdf28701bf013c013d01bdfe43fec3fec4fe418d04dbfe95fdfcfe940442fc57215c8ecaca8e5c042c80 +38222b1a1b362c2335208bc5c58b537777538bc5c58b53777753a20175020ffdf1fe8bfe8cfdf4020c0174fec4fe4301bd01 +3c013d01c0fe40feb9fefefe96016a7b755c8e018e5c000600aaff6a07ad066e0006000d00190025002b0033000001251707 +170725271505273727370110002120001110002120001310002120001110002120001321100020002521161716243736047c +01274dc6c64dfed9a0fed94dc6c64dfdf5020e01740175020cfdf4fe8bfe8cfdf28701bf013c013d01bdfe43fec3fec4fe41 +8d04dbfe95fdfcfe940442fc57215c8e01948e5c0427ce6e8b8a6ece5555ce6e8a8b6efdf50175020ffdf1fe8bfe8cfdf402 +0c0174fec4fe4301bd013c013d01c0fe40feb9fefefe96016a7b755c8e018e5c0007008fff6a07c80763000f001f002a0035 +00490057005f00000137161716043736371706070620272601100021200011102f0106212027070605343632161514062322 +2625343633321614062322260134242120041514071611100021200011103726253635342421200415141736212017262322 +07163332021d731c288f01938e271d732532b6fdfcb632feef01bf013c013d01bdde0ee5fed7fed8e60ee00394527453533a +3b51fdbe513b3a52523a3b51fe0d021e017f0180021cfde2fdf4fe8bfe8cfdf2e3fe05dbbcfe43fec3fec4fe41bdf4014a01 +4b43b0deddb0b0ddde01d1472c268d018e272c483932b5b5330151fec4fe4301bd013c013de00e39390ee02a3b51513b3a53 +533a3b5151765253025c86bebe86825cfcfea5fe8cfdf4020c0174015bfc5c02364a517272514a36cff56e6e1c00000700aa +ff6a07ad07300003000e0019001d002d0039004a000001050725013436321615140623222625343633321614062322260117 +052701371617162037363717060706202726011000212000111000212000013620172511161110002120001110371102d201 +2f4dfed1023f527453533a3b51fdbe513b3a52523a3b5103044dfed14dfdc6731c288e01948e271d732532b6fdfcb632feef +01bf013c013d01bdfe43fec3fec4fe4101e284012a8401bbadfdf4fe8bfe8cfdf2ae0567d46fd5febc3b51513b3a53533a3b +515176525301ec6ed56ffd3e472c268e8e272c483932b5b5330151fec4fe4301bd013c013d01c0fe40021d2a2aecfdd0e7fe +d1fe8cfdf4020c0174012fe70230000500aaff6a07ad066e000f001b00270032003900000137161716203736371706070620 +272601100021200011100021200003100021200011100021200001343633321614062322262d011707170725021d731c288e +01948e271d732532b6fdfcb632feef01bf013c013d01bdfe43fec3fec4fe4187020e01740175020cfdf4fe8bfe8cfdf201d8 +513b3a52523a3b5101fa01274dc6c64dfed901d1472c268e8e272c483932b5b5330151fec4fe4301bd013c013d01c0fe40fe +c30175020ffdf1fe8bfe8cfdf4020c02873b515176525364ce6e8b8a6ece000500aaff6a07ad066e000f001b00270033003f +0000013716171620373637170607062027260334363216152334262206152134363216152334262206150510002120001110 +00212000131000212000111000212000021d731c288e01948e271d732532b6fdfcb6322c8cc48c873d543d01c98cc48c873d +543dfbbd020e01740175020cfdf4fe8bfe8cfdf28701bf013c013d01bdfe43fec3fec4fe4101d1472c268e8e272c483932b5 +b53301f38bc5c58b537777538bc5c58b53777753a20175020ffdf1fe8bfe8cfdf4020c0174fec4fe4301bd013c013d01c0fe +4000000500aaff6a07ad066e000b001700370043005100000134363216152334262206152134363216152334262206150510 +0021323726270623200011331400200035331407161d01361110002120000310002120001110002120000506071617163332 +37363734272604668cc48c873d543dfd298cc48c873d543dfe9401bf013c887665412b2dfefefe9487011d0194011c877b37 +d1fe43fec3fec4fe4187020e01740175020cfdf4fe8bfe8cfdf205104f5c1f26241b100d21010102038c8bc5c58b53777753 +8bc5c58b53777753a2fec4fe4329306c05016a0102cafee5011cc9d5a0646304da0133013d01c0fe40fec30175020ffdf1fe +8bfe8cfdf4020c36432428181708133905062e00000500aaff6a07ad066e000f001b00270033003f00000137161716203736 +3717060706202726011406222635331416323635211406222635331416323635011000212000111000212000131000212000 +111000212000021d731c288e01948e271d732532b6fdfcb63204008cc48c873d543dfe378cc48c873d543dfd3f020e017401 +75020cfdf4fe8bfe8cfdf28701bf013c013d01bdfe43fec3fec4fe4101d1472c268e8e272c483932b5b53302ef8bc5c58b53 +7777538bc5c58b53777753fe620175020ffdf1fe8bfe8cfdf4020c0174fec4fe4301bd013c013d01c0fe4000000500aaff6a +07ad066e0017002f003b0047005700000132171615060f012327263526373633161716173334373621321716153336373637 +32171607140f0123272627343736011000212000111000212000131000212000111000212000133716171620373637170607 +0620272605a61a193c0132a8029f3e010a263f29201c0a010d23fd493d230d010a1c20293f260a013e9f02a832013c19fe12 +020e01740175020cfdf4fe8bfe8cfdf28701bf013c013d01bdfe43fec3fec4fe41ec731c288e01948e271d732532b6fdfcb6 +3204c00e253f413ecfbe444c151944012020310e1d47471d0e312020014419154c44becf3e413f250efe2a0175020ffdf1fe +8bfe8cfdf4020c0174fec4fe4301bd013c013d01c0fe40fdaa472c268e8e272c483932b5b533000400aaff6a07ad066e0017 +00230033003c000001100021200011342723151406222635140622263d012306071000212000111000212000253716171604 +37363717060706202726032126272621200706013101bf013c013d01bd546ea6eca6a6eca66e5587020e01740175020cfdf4 +fe8bfe8cfdf20173731c288f01938e271d732532b6fdfcb6326004941618defec2fec4e01802eafec4fe4301bd013cc3a04f +648e8e64648e8e644fa0c30175020ffdf1fe8bfe8cfdf4020c5b472c268d018e272c483932b5b533033b1a19e0e019000005 +00aaff6a07ad066e000300070011001d00290000013521152135211513323736371706070621011000212000111000212000 +131000212000111000212000049801aafbd401aa6cca8e271d732532b6fefefc7e020e01740175020cfdf4fe8bfe8cfdf287 +01bf013c013d01bdfe43fec3fec4fe41038c87878787fdac8e272c483932b502390175020ffdf1fe8bfe8cfdf4020c0174fe +c4fe4301bd013c013d01c0fe40000000000100000002599974eab4d85f0f3cf5001f080000000000d17e0ee400000000d17e +0ee4f7d6fc4c0e5909dc00000008000000000000000000010000076dfe1d00000efef7d6fa510e5900010000000000000000 +00000000000016da04cd00660000000002aa0000028b00000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000085700aa085700aa +0959005f085700aa00aa00aa00aa008f00aa00aa00aa00aa00aa00aa00aa00aa000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000080010001cc023b02ab032d0396043304b905250594061a +068a071d078607d900000001000016e60354002b0068000c00020010009900080000041502160008000400000007005a0003 +0001040900000130000000030001040900010016013000030001040900020008014600030001040900030016013000030001 +040900040016013000030001040900050018014e0003000104090006001401660043006f0070007900720069006700680074 +002000280063002900200032003000300033002000620079002000420069007400730074007200650061006d002c00200049 +006e0063002e00200041006c006c0020005200690067006800740073002000520065007300650072007600650064002e000a +0043006f00700079007200690067006800740020002800630029002000320030003000360020006200790020005400610076 +006d006a006f006e00670020004200610068002e00200041006c006c00200052006900670068007400730020005200650073 +00650072007600650064002e000a00440065006a0061005600750020006300680061006e0067006500730020006100720065 +00200069006e0020007000750062006c0069006300200064006f006d00610069006e000a00440065006a0061005600750020 +00530061006e00730042006f006f006b00560065007200730069006f006e00200032002e0033003500440065006a00610056 +007500530061006e00730002000000000000ff7e005a000000000000000000000000000000000000000016e6000000010002 +0003000400050006000700080009000a000b000c000d000e000f0010001100120013001400150016001700180019001a001b +001c001d001e001f0020002100220023002400250026002700280029002a002b002c002d002e002f00300031003200330034 +00350036003700380039003a003b003c003d003e003f0040004100420043004400450046004700480049004a004b004c004d +004e004f0050005100520053005400550056005700580059005a005b005c005d005e005f0060006100ac00a30084008500bd +009600e80086008e008b009d00a900a40102008a00da0083009300f200f3008d0097008800c300de00f1009e00aa00f500f4 +00f600a200ad00c900c700ae006200630090006400cb006500c800ca00cf00cc00cd00ce00e9006600d300d000d100af0067 +00f0009100d600d400d5006800eb00ed0089006a0069006b006d006c006e00a0006f00710070007200730075007400760077 +00ea0078007a0079007b007d007c00b800a1007f007e0080008100ec00ee00ba01030104010501060107010800fd00fe0109 +010a010b010c00ff0100010d010e010f01010110011101120113011401150116011701180119011a011b00f800f9011c011d +011e011f0120012101220123012401250126012701280129012a012b00fa00d7012c012d012e012f01300131013201330134 +01350136013701380139013a00e200e3013b013c013d013e013f014001410142014301440145014601470148014900b000b1 +014a014b014c014d014e014f015001510152015300fb00fc00e400e5015401550156015701580159015a015b015c015d015e +015f016001610162016301640165016601670168016900bb016a016b016c016d00e600e7016e016f01700171017201730174 +01750176017701780179017a017b017c017d017e017f018000a6018101820183018401850186018701880189018a018b018c +018d018e018f0190019101920193019401950196019701980199019a019b019c019d019e019f01a001a101a201a301a401a5 +01a601a701a801a901aa01ab01ac01ad01ae01af01b001b101b201b301b401b501b601b701b801b901ba01bb01bc01bd01be +01bf01c001c101c201c301c401c501c601c701c801c901ca01cb01cc01cd01ce01cf01d001d101d201d301d401d501d601d7 +01d801d901da01db01dc01dd01de01df01e001e101e201e301e401e501e601e701e801e901ea01eb01ec01ed01ee01ef01f0 +01f101f201f301f401f501f601f701f801f901fa01fb01fc01fd01fe01ff0200020102020203020402050206020702080209 +020a020b020c020d020e020f0210021102120213021402150216021702180219021a021b021c021d021e021f022002210222 +0223022402250226022702280229022a022b022c022d022e022f0230023102320233023402350236023702380239023a023b +023c023d023e023f0240024102420243024402450246024702480249024a024b024c024d024e024f02500251025202530254 +02550256025702580259025a025b025c025d025e025f0260026102620263026402650266026702680269026a026b026c026d +026e026f0270027102720273027402750276027702780279027a027b027c027d027e027f0280028102820283028402850286 +028702880289028a028b028c028d028e028f0290029102920293029402950296029702980299029a029b029c029d029e029f +02a002a102a202a302a402a502a602a702a802a902aa02ab02ac02ad02ae02af02b002b102b202b300d800e102b402b502b6 +02b702b802b902ba02bb02bc02bd02be02bf02c002c102c202c300db00dc00dd00e000d900df02c402c502c602c702c802c9 +02ca02cb02cc02cd02ce02cf02d002d102d202d302d402d502d602d702d802d902da02db02dc02dd02de02df02e002e102e2 +02e302e402e502e602e702e802e902ea02eb02ec02ed02ee02ef02f002f102f202f302f402f502f602f702f802f902fa02fb +02fc02fd02fe02ff0300030103020303030403050306030703080309030a030b030c030d030e030f03100311031203130314 +03150316031703180319031a031b031c031d031e031f0320032103220323032403250326032703280329032a032b032c032d +032e032f0330033103320333033403350336033703380339033a033b033c033d033e033f0340034103420343034403450346 +034703480349034a034b034c034d034e034f0350035103520353035403550356035703580359035a035b035c035d035e035f +0360009f036103620363036403650366036703680369036a036b036c036d036e036f0370037103720373037403750376009b +037703780379037a037b037c037d037e037f0380038103820383038403850386038703880389038a038b038c038d038e038f +0390039103920393039403950396039703980399039a039b039c039d039e039f03a003a103a203a303a403a503a603a703a8 +03a903aa03ab03ac03ad03ae03af03b003b103b203b303b403b503b603b703b803b903ba03bb03bc03bd03be03bf03c003c1 +03c203c303c403c503c603c703c803c903ca03cb03cc03cd03ce03cf03d003d103d203d303d403d503d603d703d803d903da +03db03dc03dd03de03df03e003e103e203e303e403e503e603e703e803e903ea03eb03ec03ed03ee03ef03f003f103f203f3 +03f403f503f603f703f803f903fa03fb03fc03fd03fe03ff0400040104020403040404050406040704080409040a040b040c +040d040e040f0410041104120413041404150416041704180419041a041b041c041d041e041f042004210422042304240425 +0426042704280429042a042b042c042d042e042f0430043104320433043404350436043704380439043a043b043c043d043e +043f0440044104420443044404450446044704480449044a044b044c044d044e044f04500451045204530454045504560457 +04580459045a045b045c045d045e045f0460046104620463046404650466046704680469046a046b046c046d046e046f0470 +047104720473047404750476047704780479047a047b047c047d047e047f0480048104820483048404850486048704880489 +048a048b048c048d048e048f0490049104920493049404950496049704980499049a049b049c049d049e049f04a004a104a2 +04a304a404a504a604a704a804a904aa04ab04ac04ad04ae04af04b004b104b204b304b404b504b604b704b804b904ba04bb +04bc04bd04be04bf04c004c104c204c304c404c504c604c704c804c904ca04cb04cc04cd04ce04cf04d004d104d204d304d4 +04d504d604d704d804d904da04db04dc04dd04de04df04e004e104e204e304e404e504e604e704e804e904ea04eb04ec04ed +04ee04ef04f004f104f204f304f404f504f604f704f804f904fa04fb04fc04fd04fe04ff0500050105020503050405050506 +050705080509050a050b050c050d050e050f0510051105120513051405150516051705180519051a051b051c051d051e051f +0520052105220523052405250526052705280529052a052b052c052d052e052f053005310532053305340535053605370538 +0539053a053b053c053d053e053f0540054105420543054405450546054705480549054a054b054c054d054e054f05500551 +05520553055405550556055705580559055a055b055c055d055e055f0560056105620563056405650566056705680569056a +056b056c056d056e056f0570057105720573057405750576057705780579057a057b057c057d057e057f0580058105820583 +058405850586058705880589058a058b058c058d058e058f0590059105920593059405950596059705980599059a059b059c +059d059e059f05a005a105a205a305a405a505a605a705a805a905aa05ab05ac05ad05ae05af05b005b105b205b305b405b5 +05b605b705b805b905ba05bb05bc05bd05be05bf05c005c105c205c305c405c505c605c705c805c905ca05cb05cc05cd05ce +05cf05d005d105d205d305d405d505d605d705d805d905da05db05dc05dd05de05df05e005e105e205e305e405e505e605e7 +05e805e905ea05eb05ec05ed05ee05ef05f005f105f205f305f405f505f605f705f805f905fa05fb05fc05fd05fe05ff0600 +060106020603060406050606060706080609060a060b060c060d060e060f0610061106120613061406150616061706180619 +061a061b061c061d061e061f0620062106220623062406250626062706280629062a062b062c062d062e062f063006310632 +0633063406350636063706380639063a063b063c063d063e063f0640064106420643064406450646064706480649064a064b +064c064d064e064f0650065106520653065406550656065706580659065a065b065c065d065e065f06600661066206630664 +06650666066706680669066a066b066c066d066e066f0670067106720673067406750676067706780679067a067b067c067d +067e067f0680068106820683068406850686068706880689068a068b068c068d068e068f0690069106920693069406950696 +069706980699069a069b069c069d069e069f06a006a106a206a306a406a506a606a706a806a906aa06ab06ac06ad06ae06af +06b006b106b206b306b406b506b606b706b806b906ba06bb06bc06bd06be06bf06c006c106c206c306c406c506c606c706c8 +06c906ca06cb06cc06cd06ce06cf06d006d106d206d306d406d506d606d706d806d906da06db06dc06dd06de06df06e006e1 +06e206e306e406e506e606e706e806e906ea06eb06ec06ed06ee06ef06f006f106f206f306f406f506f606f706f806f906fa +06fb06fc06fd06fe06ff0700070107020703070407050706070707080709070a070b070c070d070e070f0710071107120713 +071407150716071707180719071a071b071c071d071e071f0720072107220723072407250726072707280729072a072b072c +072d072e072f0730073107320733073407350736073707380739073a073b073c073d073e073f074007410742074307440745 +0746074707480749074a074b074c074d074e074f0750075107520753075407550756075707580759075a075b075c075d075e +075f0760076107620763076407650766076707680769076a076b076c076d076e076f07700771077207730774077507760777 +07780779077a077b077c077d077e077f0780078107820783078407850786078707880789078a078b078c078d078e078f0790 +079107920793079407950796079707980799079a079b079c079d079e079f07a007a107a207a307a407a507a607a707a807a9 +07aa07ab07ac07ad07ae07af07b007b107b207b307b407b507b607b707b807b907ba07bb07bc07bd07be07bf07c007c107c2 +07c307c407c507c607c707c807c907ca07cb07cc07cd07ce07cf07d007d107d207d307d407d507d607d707d807d907da07db +07dc07dd07de07df07e007e107e207e307e407e507e607e707e807e907ea07eb07ec07ed07ee07ef07f007f107f207f307f4 +07f507f607f707f807f907fa07fb07fc07fd07fe07ff0800080108020803080408050806080708080809080a080b080c080d +080e080f0810081108120813081408150816081708180819081a081b081c081d081e081f0820082108220823082408250826 +082708280829082a082b082c082d082e082f0830083108320833083408350836083708380839083a083b083c083d083e083f +0840084108420843084408450846084708480849084a084b084c084d084e084f085008510852085308540855085608570858 +0859085a085b085c085d085e085f0860086108620863086408650866086708680869086a086b086c086d086e086f08700871 +08720873087408750876087708780879087a087b087c087d087e087f0880088108820883088408850886088708880889088a +088b088c088d088e088f0890089108920893089408950896089708980899089a089b089c089d089e089f08a008a108a208a3 +08a408a508a608a708a808a908aa08ab08ac08ad08ae08af08b008b108b208b308b408b508b608b708b808b908ba08bb08bc +08bd08be08bf08c008c108c208c308c408c508c608c708c808c908ca08cb08cc08cd08ce08cf08d008d108d208d308d408d5 +08d608d708d808d908da08db08dc08dd08de08df08e008e108e208e308e408e508e608e708e808e908ea08eb08ec08ed08ee +08ef08f008f108f208f308f408f508f608f708f808f908fa08fb08fc08fd08fe08ff09000901090209030904090509060907 +09080909090a090b090c090d090e090f0910091109120913091409150916091709180919091a091b091c091d091e091f0920 +092109220923092409250926092709280929092a092b092c092d092e092f0930093109320933093409350936093709380939 +093a093b093c093d093e093f0940094109420943094409450946094709480949094a094b094c094d094e094f095009510952 +0953095409550956095709580959095a095b095c095d095e095f0960096109620963096409650966096709680969096a096b +096c096d096e096f0970097109720973097409750976097709780979097a097b097c097d097e097f09800981098209830984 +09850986098709880989098a098b098c098d098e098f0990099109920993099409950996099709980999099a099b099c099d +099e099f09a009a109a209a309a409a509a609a709a809a909aa09ab09ac09ad09ae09af09b009b109b209b309b409b509b6 +09b709b809b909ba09bb09bc09bd09be09bf09c009c109c209c309c409c509c609c709c809c909ca09cb09cc09cd09ce09cf +09d009d109d209d309d409d509d609d709d809d909da09db09dc09dd09de09df09e009e109e209e309e409e509e609e709e8 +09e909ea09eb09ec09ed09ee09ef09f009f109f209f309f409f509f609f709f809f909fa09fb09fc09fd09fe09ff0a000a01 +0a020a030a040a050a060a070a080a090a0a0a0b0a0c0a0d0a0e0a0f0a100a110a120a130a140a150a160a170a180a190a1a +0a1b0a1c0a1d0a1e0a1f0a200a210a220a230a240a250a260a270a280a290a2a0a2b0a2c0a2d0a2e0a2f0a300a310a320a33 +0a340a350a360a370a380a390a3a0a3b0a3c0a3d0a3e0a3f0a400a410a420a430a440a450a460a470a480a490a4a0a4b0a4c +0a4d0a4e0a4f0a500a510a520a530a540a550a560a570a580a590a5a0a5b0a5c0a5d0a5e0a5f0a600a610a620a630a640a65 +0a660a670a680a690a6a0a6b0a6c0a6d0a6e0a6f0a700a710a720a730a740a750a760a770a780a790a7a0a7b0a7c0a7d0a7e +0a7f0a800a810a820a830a840a850a860a870a880a890a8a0a8b0a8c0a8d0a8e0a8f0a900a910a920a930a940a950a960a97 +0a980a990a9a0a9b0a9c0a9d0a9e0a9f0aa00aa10aa20aa30aa40aa50aa60aa70aa80aa90aaa0aab0aac0aad0aae0aaf0ab0 +0ab10ab20ab30ab40ab50ab60ab70ab80ab90aba0abb0abc0abd0abe0abf0ac00ac10ac20ac30ac40ac50ac60ac70ac80ac9 +0aca0acb0acc0acd0ace0acf0ad00ad10ad20ad30ad40ad50ad60ad70ad80ad90ada0adb0adc0add0ade0adf0ae00ae10ae2 +0ae30ae40ae50ae60ae70ae80ae90aea0aeb0aec0aed0aee0aef0af00af10af20af30af40af50af60af70af80af90afa0afb +0afc0afd0afe0aff0b000b010b020b030b040b050b060b070b080b090b0a0b0b0b0c0b0d0b0e0b0f0b100b110b120b130b14 +0b150b1600b200b30b170b180b1900b600b700c40b1a00b400b500c50b1b008200c200870b1c0b1d0b1e00ab0b1f0b200b21 +0b220b230b240b250b260b2700c60b280b290b2a0b2b0b2c0b2d0b2e0b2f00be00bf0b300b310b320b330b340b350b360b37 +0b3800bc0b390b3a0b3b0b3c0b3d0b3e0b3f0b400b410b420b430b440b450b460b470b480b490b4a0b4b0b4c0b4d0b4e0b4f +0b500b510b520b530b540b550b560b570b580b590b5a0b5b0b5c0b5d0b5e0b5f0b600b610b620b630b640b650b660b670b68 +0b690b6a0b6b0b6c0b6d0b6e0b6f0b700b710b720b730b740b750b760b770b780b790b7a0b7b0b7c0b7d0b7e0b7f0b800b81 +0b820b830b840b850b860b870b880b890b8a0b8b00f70b8c0b8d0b8e0b8f0b900b910b920b930b940b950b960b970b980b99 +0b9a0b9b0b9c0b9d0b9e0b9f0ba00ba10ba20ba30ba40ba50ba60ba70ba80ba90baa0bab0bac0bad0bae0baf0bb00bb10bb2 +0bb30bb40bb50bb60bb70bb80bb90bba0bbb0bbc0bbd0bbe0bbf0bc00bc10bc20bc30bc40bc50bc60bc70bc80bc9008c0bca +0bcb0bcc0bcd0bce0bcf0bd00bd10bd20bd30bd40bd50bd60bd70bd80bd90bda0bdb0bdc0bdd0bde0bdf0be00be10be20be3 +0be40be50be60be70be80be90bea0beb0bec0bed0bee0bef0bf00bf10bf20bf30bf40bf50bf60bf70bf80bf90bfa0bfb0bfc +0bfd0bfe0bff0c000c010c020c030c040c050c060c070c080c090c0a0c0b0c0c0c0d0c0e0c0f0c100c110c120c130c140c15 +0c160c170c180c190c1a0c1b0c1c0c1d0c1e0c1f0c200c210c220c230c240c250c260c270c280c290c2a0c2b0c2c0c2d0c2e +0c2f0c300c310c320c330c340c350c360c370c380c390c3a0c3b0c3c0c3d0c3e0c3f0c400c410c420c430c440c450c460c47 +0c480c490c4a0c4b0c4c0c4d0c4e0c4f0c500c510c520c530c540c550c560c570c580c590c5a0c5b0c5c0c5d0c5e0c5f0c60 +0c610c620c630c640c650c660c670c680c690c6a0c6b0c6c0c6d0c6e0c6f0c700c710c720c730c740c750c760c770c780c79 +0c7a0c7b0c7c0c7d0c7e0c7f0c800c810c820c830c840c850c860c870c880c890c8a0c8b0c8c0c8d0c8e0c8f0c900c910c92 +0c930c940c950c960c970c980c990c9a0c9b00980c9c0c9d0c9e00a80c9f0ca00ca10ca20ca30ca40ca50ca6009a0ca70099 +00ef0ca80ca90caa0cab0cac0cad0cae00a50caf0cb00cb100920cb20cb30cb40cb50cb60cb70cb80cb90cba0cbb0cbc0cbd +009c0cbe0cbf0cc00cc10cc20cc30cc40cc50cc60cc70cc80cc90cca0ccb0ccc0ccd0cce0ccf0cd00cd10cd20cd30cd40cd5 +0cd60cd70cd80cd900a70cda0cdb0cdc0cdd0cde0cdf0ce00ce10ce20ce30ce40ce50ce60ce70ce80ce90cea0ceb0cec0ced +0cee0cef0cf0008f0cf10cf20cf3009400950cf40cf50cf60cf70cf80cf90cfa0cfb0cfc0cfd0cfe0cff0d000d010d020d03 +0d040d050d060d070d080d090d0a0d0b0d0c0d0d0d0e0d0f0d100d110d120d130d140d150d160d170d180d190d1a0d1b0d1c +0d1d0d1e0d1f0d200d210d220d230d240d250d260d270d280d290d2a0d2b0d2c0d2d0d2e0d2f0d300d310d320d330d340d35 +0d360d370d380d390d3a0d3b0d3c0d3d0d3e0d3f0d400d410d420d430d440d450d460d470d480d490d4a0d4b0d4c0d4d0d4e +0d4f0d500d510d520d530d540d550d560d570d580d590d5a0d5b0d5c0d5d0d5e0d5f0d600d610d620d630d640d650d660d67 +0d680d690d6a0d6b0d6c0d6d0d6e0d6f0d700d710d720d730d740d750d760d770d780d790d7a0d7b0d7c0d7d0d7e0d7f0d80 +0d810d820d830d840d850d860d870d880d890d8a0d8b0d8c0d8d0d8e0d8f0d900d910d920d930d940d950d960d970d980d99 +0d9a0d9b0d9c0d9d0d9e0d9f0da00da10da20da30da40da50da60da70da80da90daa0dab0dac0dad0dae0daf0db00db10db2 +0db30db40db50db60db70db80db90dba0dbb0dbc0dbd0dbe0dbf0dc00dc10dc20dc30dc40dc50dc60dc70dc80dc90dca0dcb +0dcc0dcd0dce0dcf0dd00dd10dd20dd30dd40dd50dd60dd70dd80dd90dda0ddb0ddc0ddd0dde0ddf0de00de10de20de30de4 +0de50de60de70de80de90dea0deb0dec0ded0dee0def0df00df10df20df30df40df50df60df70df80df90dfa0dfb0dfc0dfd +0dfe0dff0e000e010e020e030e040e050e060e070e080e090e0a0e0b0e0c0e0d0e0e0e0f0e100e110e120e130e140e150e16 +0e170e180e190e1a0e1b0e1c0e1d0e1e0e1f0e200e210e220e230e240e250e260e270e280e290e2a0e2b0e2c0e2d0e2e0e2f +0e300e310e320e330e340e350e360e370e380e390e3a0e3b0e3c0e3d0e3e0e3f0e400e410e420e430e440e450e460e470e48 +0e490e4a0e4b0e4c0e4d0e4e0e4f0e500e510e520e530e540e550e560e570e580e590e5a0e5b0e5c0e5d0e5e0e5f0e600e61 +0e620e630e640e650e660e670e680e690e6a0e6b0e6c0e6d0e6e0e6f0e700e710e720e730e740e750e760e770e780e790e7a +0e7b0e7c0e7d0e7e0e7f0e800e810e820e830e840e850e860e870e880e890e8a0e8b0e8c0e8d0e8e0e8f0e900e910e920e93 +0e940e950e960e970e980e990e9a0e9b0e9c0e9d0e9e0e9f0ea00ea10ea20ea30ea400b90ea50ea60ea70ea80ea90eaa0eab +0eac0ead0eae0eaf0eb00eb10eb20eb30eb40eb50eb60eb70eb80eb90eba0ebb0ebc0ebd0ebe0ebf0ec00ec10ec20ec30ec4 +0ec50ec60ec70ec80ec90eca0ecb0ecc0ecd0ece0ecf0ed00ed10ed20ed30ed40ed50ed60ed70ed80ed90eda0edb0edc0edd +0ede0edf0ee00ee10ee20ee30ee40ee50ee60ee70ee80ee90eea0eeb0eec0eed0eee0eef0ef00ef10ef20ef30ef40ef50ef6 +0ef70ef80ef90efa0efb0efc0efd0efe0eff0f000f010f020f030f040f050f060f070f080f090f0a0f0b0f0c0f0d0f0e0f0f +0f100f110f120f130f140f150f160f170f180f190f1a0f1b0f1c0f1d0f1e0f1f0f200f210f220f230f240f250f260f270f28 +0f290f2a0f2b0f2c0f2d0f2e0f2f0f300f310f320f330f340f350f360f370f380f390f3a0f3b0f3c0f3d0f3e0f3f0f400f41 +0f420f430f440f450f460f470f480f490f4a0f4b0f4c0f4d0f4e0f4f0f500f510f520f530f540f550f560f570f580f590f5a +0f5b0f5c0f5d0f5e0f5f0f600f610f620f630f640f650f660f670f680f690f6a0f6b0f6c0f6d0f6e0f6f0f700f710f720f73 +0f740f750f760f770f780f790f7a0f7b0f7c0f7d0f7e0f7f0f800f810f820f830f840f850f860f870f880f890f8a0f8b0f8c +0f8d0f8e0f8f0f900f910f920f930f940f950f960f970f980f990f9a0f9b0f9c0f9d0f9e0f9f0fa00fa10fa20fa30fa40fa5 +0fa60fa70fa80fa90faa0fab0fac0fad0fae0faf0fb00fb10fb20fb30fb40fb50fb60fb70fb80fb90fba0fbb0fbc0fbd0fbe +0fbf0fc00fc10fc20fc30fc40fc50fc60fc70fc80fc90fca0fcb0fcc0fcd0fce0fcf0fd00fd10fd20fd30fd40fd50fd60fd7 +0fd80fd90fda0fdb0fdc0fdd0fde0fdf0fe00fe10fe20fe30fe40fe50fe60fe70fe80fe90fea0feb0fec0fed0fee0fef0ff0 +0ff10ff20ff30ff40ff50ff60ff70ff80ff90ffa0ffb0ffc0ffd0ffe0fff1000100110021003100410051006100710081009 +100a100b100c100d100e100f1010101110121013101410151016101710181019101a101b101c101d101e101f102010211022 +1023102410251026102710281029102a102b102c102d102e102f1030103110321033103410351036103710381039103a103b +103c103d103e103f1040104110421043104410451046104710481049104a104b104c104d104e104f10501051105210531054 +10551056105710581059105a105b105c105d105e105f1060106110621063106410651066106710681069106a106b106c106d +106e106f1070107110721073107410751076107710781079107a107b107c107d107e107f1080108110821083108410851086 +108710881089108a108b108c108d108e108f1090109110921093109410951096109710981099109a109b109c109d109e109f +10a010a110a210a310a410a510a610a710a810a910aa10ab10ac10ad10ae10af10b010b110b210b310b410b510b610b710b8 +10b910ba10bb10bc10bd10be10bf10c010c110c210c310c410c510c610c710c810c910ca10cb10cc10cd10ce10cf10d010d1 +10d210d310d410d510d610d710d810d910da10db10dc10dd10de10df10e010e110e210e310e410e510e610e710e810e910ea +10eb10ec10ed10ee10ef10f010f110f210f310f410f510f610f710f810f910fa10fb10fc10fd10fe10ff1100110111021103 +110411051106110711081109110a110b110c110d110e110f1110111111121113111411151116111711181119111a111b111c +111d111e111f1120112111221123112411251126112711281129112a112b112c112d112e112f113011311132113311341135 +1136113711381139113a113b113c113d113e113f1140114111421143114411451146114711481149114a114b114c114d114e +114f1150115111521153115411551156115711581159115a115b115c115d115e115f11601161116211631164116511661167 +11681169116a116b116c116d116e116f1170117111721173117411751176117711781179117a117b117c117d117e117f1180 +118111821183118411851186118711881189118a118b118c118d118e118f1190119111921193119411951196119711981199 +119a119b119c119d119e119f11a011a111a211a311a411a511a611a711a811a911aa11ab11ac11ad11ae11af11b011b111b2 +11b311b411b511b611b711b811b911ba11bb11bc11bd11be11bf11c011c111c211c311c411c511c611c711c811c911ca11cb +11cc11cd11ce11cf11d011d111d211d311d411d511d611d711d811d911da11db11dc11dd11de11df11e011e111e211e311e4 +11e511e611e711e811e911ea11eb11ec11ed11ee11ef11f011f111f211f311f411f511f611f711f811f911fa11fb11fc11fd +11fe11ff1200120112021203120412051206120712081209120a120b120c120d120e120f1210121112121213121412151216 +121712181219121a121b121c121d121e121f1220122112221223122412251226122712281229122a122b122c122d122e122f +1230123112321233123412351236123712381239123a123b123c123d123e123f124012411242124312441245124612471248 +1249124a124b124c124d124e124f1250125112521253125412551256125712581259125a125b125c125d125e125f12601261 +12621263126412651266126712681269126a126b126c126d126e126f1270127112721273127412751276127712781279127a +127b127c127d127e127f1280128112821283128412851286128712881289128a128b128c128d128e128f1290129112921293 +129412951296129712981299129a129b129c129d129e129f12a012a112a212a312a412a512a612a712a812a912aa12ab12ac +12ad12ae12af12b012b112b212b312b412b512b612b712b812b912ba12bb12bc12bd12be12bf12c012c112c212c312c412c5 +12c612c712c812c912ca12cb12cc12cd12ce12cf12d012d112d212d312d412d512d612d712d812d912da12db12dc12dd12de +12df12e012e112e212e312e412e512e612e712e812e912ea12eb12ec12ed12ee12ef12f012f112f212f312f412f512f612f7 +12f812f912fa12fb12fc12fd12fe12ff1300130113021303130413051306130713081309130a130b130c130d130e130f1310 +131113121313131413151316131713181319131a131b131c131d131e131f1320132113221323132413251326132713281329 +132a132b132c132d132e132f1330133113321333133413351336133713381339133a133b133c133d133e133f134013411342 +1343134413451346134713481349134a134b134c134d134e134f1350135113521353135413551356135713581359135a135b +135c135d135e135f1360136113621363136413651366136713681369136a136b136c136d136e136f13701371137213731374 +13751376137713781379137a137b137c137d137e137f1380138113821383138413851386138713881389138a138b138c138d +138e138f1390139113921393139413951396139713981399139a139b139c139d139e139f13a013a113a213a313a413a513a6 +13a713a813a913aa13ab13ac13ad13ae13af13b013b100c000c113b213b313b413b513b613b713b813b913ba13bb13bc13bd +13be13bf13c013c113c213c313c413c513c613c713c813c913ca13cb13cc13cd13ce13cf13d013d113d213d313d413d513d6 +13d713d813d913da13db13dc13dd13de13df13e013e113e213e313e413e513e613e713e813e913ea13eb13ec13ed13ee13ef +13f013f113f213f313f413f513f613f713f813f913fa13fb13fc13fd13fe13ff140014011402140314041405140614071408 +1409140a140b140c140d140e140f1410141114121413141414151416141714181419141a141b141c141d141e141f14201421 +14221423142414251426142714281429142a142b142c142d142e142f1430143114321433143414351436143714381439143a +143b143c143d143e143f1440144114421443144414451446144714481449144a144b144c144d144e144f1450145114521453 +145414551456145714581459145a145b145c145d145e145f1460146114621463146414651466146714681469146a146b146c +146d146e146f1470147114721473147414751476147714781479147a147b147c147d147e147f148014811482148314841485 +1486148714881489148a148b148c148d148e148f1490149114921493149414951496149714981499149a149b149c149d149e +149f14a014a114a214a314a414a514a614a714a814a914aa14ab14ac14ad14ae14af14b014b114b214b314b414b514b614b7 +14b814b914ba14bb14bc14bd14be14bf14c014c114c214c314c414c514c614c714c814c914ca14cb14cc14cd14ce14cf14d0 +14d114d214d314d414d514d614d714d814d914da14db14dc14dd14de14df14e014e114e214e314e414e514e614e714e814e9 +14ea14eb14ec14ed14ee14ef14f014f114f214f314f414f514f614f714f814f914fa14fb14fc14fd14fe14ff150015011502 +1503150415051506150715081509150a150b150c150d150e150f1510151115121513151415151516151715181519151a151b +151c151d151e151f1520152115221523152415251526152715281529152a152b152c152d152e152f15301531153215331534 +15351536153715381539153a153b153c153d153e153f1540154115421543154415451546154715481549154a154b154c154d +154e154f1550155115521553155415551556155715581559155a155b155c155d155e155f1560156115621563156415651566 +156715681569156a156b156c156d156e156f1570157115721573157415751576157715781579157a157b157c157d157e157f +1580158115821583158415851586158715881589158a158b158c158d158e158f159015911592159315941595159615971598 +1599159a159b159c159d159e159f15a015a115a215a315a415a515a615a715a815a915aa15ab15ac15ad15ae15af15b015b1 +15b215b315b415b515b615b715b815b915ba15bb15bc15bd15be15bf15c015c115c215c315c415c515c615c715c815c915ca +15cb15cc15cd15ce15cf15d015d115d215d315d415d515d615d715d815d915da15db15dc15dd15de15df15e015e115e215e3 +15e415e515e615e715e815e915ea15eb15ec15ed15ee15ef15f015f115f215f315f415f515f615f715f815f915fa15fb15fc +15fd15fe15ff1600160116021603160416051606160716081609160a160b160c160d160e160f161016111612161316141615 +1616161716181619161a161b161c161d161e161f1620162116221623162416251626162716281629162a162b162c162d162e +162f1630163116321633163416351636163716381639163a163b163c163d163e163f16401641164216431644164516461647 +16481649164a164b164c164d164e164f1650165116521653165416551656165716581659165a165b165c165d165e165f1660 +166116621663166416651666166716681669166a166b166c166d166e166f1670167116721673167416751676167716781679 +167a167b167c167d167e167f1680168116821683168416851686168716881689168a168b168c168d168e168f169016911692 +1693169416951696169716981699169a169b169c169d169e169f16a016a116a216a316a416a516a616a716a816a916aa16ab +16ac16ad16ae16af16b016b116b216b316b416b516b616b716b816b916ba16bb16bc16bd16be16bf16c016c116c216c316c4 +16c516c616c716c816c916ca16cb16cc16cd16ce16cf16d016d116d216d316d416d516d616d716d816d916da16db16dc16dd +16de16df16e016e116e216e316e416e516e60973667468797068656e07416d6163726f6e07616d6163726f6e064162726576 +650661627265766507416f676f6e656b07616f676f6e656b0b4363697263756d666c65780b6363697263756d666c65780a43 +646f74616363656e740a63646f74616363656e7406446361726f6e06646361726f6e064463726f617407456d6163726f6e07 +656d6163726f6e06456272657665066562726576650a45646f74616363656e740a65646f74616363656e7407456f676f6e65 +6b07656f676f6e656b06456361726f6e06656361726f6e0b4763697263756d666c65780b6763697263756d666c65780a4764 +6f74616363656e740a67646f74616363656e740c47636f6d6d61616363656e740c67636f6d6d61616363656e740b48636972 +63756d666c65780b6863697263756d666c657804486261720468626172064974696c6465066974696c646507496d6163726f +6e07696d6163726f6e064962726576650669627265766507496f676f6e656b07696f676f6e656b02494a02696a0b4a636972 +63756d666c65780b6a63697263756d666c65780c4b636f6d6d61616363656e740c6b636f6d6d61616363656e740c6b677265 +656e6c616e646963064c6163757465066c61637574650c4c636f6d6d61616363656e740c6c636f6d6d61616363656e74064c +6361726f6e066c6361726f6e044c646f74046c646f74064e6163757465066e61637574650c4e636f6d6d61616363656e740c +6e636f6d6d61616363656e74064e6361726f6e066e6361726f6e0b6e61706f7374726f70686503456e6703656e67074f6d61 +63726f6e076f6d6163726f6e064f6272657665066f62726576650d4f68756e676172756d6c6175740d6f68756e676172756d +6c61757406526163757465067261637574650c52636f6d6d61616363656e740c72636f6d6d61616363656e7406526361726f +6e06726361726f6e06536163757465067361637574650b5363697263756d666c65780b7363697263756d666c65780c54636f +6d6d61616363656e740c74636f6d6d61616363656e7406546361726f6e06746361726f6e0454626172047462617206557469 +6c6465067574696c646507556d6163726f6e07756d6163726f6e0655627265766506756272657665055572696e6705757269 +6e670d5568756e676172756d6c6175740d7568756e676172756d6c61757407556f676f6e656b07756f676f6e656b0b576369 +7263756d666c65780b7763697263756d666c65780b5963697263756d666c65780b7963697263756d666c6578065a61637574 +65067a61637574650a5a646f74616363656e740a7a646f74616363656e74056c6f6e677307756e693031383007756e693031 +383107756e693031383207756e693031383307756e693031383407756e693031383507756e693031383607756e6930313837 +07756e693031383807756e693031383907756e693031384107756e693031384207756e693031384307756e69303138440775 +6e693031384507756e693031384607756e693031393007756e693031393107756e693031393307756e693031393407756e69 +3031393507756e693031393607756e693031393707756e693031393807756e693031393907756e693031394107756e693031 +394207756e693031394307756e693031394407756e693031394507756e6930313946054f686f726e056f686f726e07756e69 +3031413207756e693031413307756e693031413407756e693031413507756e693031413607756e693031413707756e693031 +413807756e693031413907756e693031414107756e693031414207756e693031414307756e693031414407756e6930314145 +0555686f726e0575686f726e07756e693031423107756e693031423207756e693031423307756e693031423407756e693031 +423507756e693031423607756e693031423707756e693031423807756e693031423907756e693031424107756e6930314242 +07756e693031424307756e693031424407756e693031424507756e693031424607756e693031433007756e69303143310775 +6e693031433207756e693031433307756e693031433407756e693031433507756e693031433607756e693031433707756e69 +3031433807756e693031433907756e693031434107756e693031434207756e693031434307756e693031434407756e693031 +434507756e693031434607756e693031443007756e693031443107756e693031443207756e693031443307756e6930314434 +07756e693031443507756e693031443607756e693031443707756e693031443807756e693031443907756e69303144410775 +6e693031444207756e693031444307756e693031444407756e693031444507756e693031444607756e693031453007756e69 +3031453107756e693031453207756e693031453307756e693031453407756e693031453506476361726f6e06676361726f6e +07756e693031453807756e693031453907756e693031454107756e693031454207756e693031454307756e69303145440775 +6e693031454507756e693031454607756e693031463007756e693031463107756e693031463207756e693031463307756e69 +3031463407756e693031463507756e693031463607756e693031463707756e693031463807756e69303146390a4172696e67 +61637574650a6172696e676163757465074145616375746507616561637574650b4f736c61736861637574650b6f736c6173 +68616375746507756e693032303007756e693032303107756e693032303207756e693032303307756e693032303407756e69 +3032303507756e693032303607756e693032303707756e693032303807756e693032303907756e693032304107756e693032 +304207756e693032304307756e693032304407756e693032304507756e693032304607756e693032313007756e6930323131 +07756e693032313207756e693032313307756e693032313407756e693032313507756e693032313607756e69303231370c53 +636f6d6d61616363656e740c73636f6d6d61616363656e7407756e693032314107756e693032314207756e69303231430775 +6e693032314407756e693032314507756e693032314607756e693032323007756e693032323107756e693032323207756e69 +3032323307756e693032323407756e693032323507756e693032323607756e693032323707756e693032323807756e693032 +323907756e693032324107756e693032324207756e693032324307756e693032324407756e693032324507756e6930323246 +07756e693032333007756e693032333107756e693032333207756e693032333307756e693032333407756e69303233350775 +6e693032333608646f746c6573736a07756e693032333807756e693032333907756e693032334107756e693032334207756e +693032334307756e693032334407756e693032334507756e693032334607756e693032343007756e693032343107756e6930 +32343207756e693032343307756e693032343407756e693032343507756e693032343607756e693032343707756e69303234 +3807756e693032343907756e693032344107756e693032344207756e693032344307756e693032344407756e693032344507 +756e693032344607756e693032353007756e693032353107756e693032353207756e693032353307756e693032353407756e +693032353507756e693032353607756e693032353707756e693032353807756e693032353907756e693032354107756e6930 +32354207756e693032354307756e693032354407756e693032354507756e693032354607756e693032363007756e69303236 +3107756e693032363207756e693032363307756e693032363407756e693032363507756e693032363607756e693032363707 +756e693032363807756e693032363907756e693032364107756e693032364207756e693032364307756e693032364407756e +693032364507756e693032364607756e693032373007756e693032373107756e693032373207756e693032373307756e6930 +32373407756e693032373507756e693032373607756e693032373707756e693032373807756e693032373907756e69303237 +4107756e693032374207756e693032374307756e693032374407756e693032374507756e693032374607756e693032383007 +756e693032383107756e693032383207756e693032383307756e693032383407756e693032383507756e693032383607756e +693032383707756e693032383807756e693032383907756e693032384107756e693032384207756e693032384307756e6930 +32384407756e693032384507756e693032384607756e693032393007756e693032393107756e693032393207756e69303239 +3307756e693032393407756e693032393507756e693032393607756e693032393707756e693032393807756e693032393907 +756e693032394107756e693032394207756e693032394307756e693032394407756e693032394507756e693032394607756e +693032413007756e693032413107756e693032413207756e693032413307756e693032413407756e693032413507756e6930 +32413607756e693032413707756e693032413807756e693032413907756e693032414107756e693032414207756e69303241 +4307756e693032414407756e693032414507756e693032414607756e693032423007756e693032423107756e693032423207 +756e693032423307756e693032423407756e693032423507756e693032423607756e693032423707756e693032423807756e +693032423907756e693032424107756e693032424207756e693032424307756e693032424407756e693032424507756e6930 +32424607756e693032433007756e693032433107756e693032433207756e693032433307756e693032433407756e69303243 +3507756e693032433807756e693032433907756e693032434107756e693032434207756e693032434307756e693032434407 +756e693032434507756e693032434607756e693032443007756e693032443107756e693032443207756e693032443307756e +693032443407756e693032443507756e693032443607756e693032443707756e693032444507756e693032444607756e6930 +32453007756e693032453107756e693032453207756e693032453307756e693032453407756e693032453507756e69303245 +3607756e693032453707756e693032453807756e693032453907756e693032454307756e693032454407756e693032454507 +756e693032463307756e6930324637096772617665636f6d62096163757465636f6d6207756e69303330320974696c646563 +6f6d6207756e693033303407756e693033303507756e693033303607756e693033303707756e69303330380d686f6f6b6162 +6f7665636f6d6207756e693033304107756e693033304207756e693033304307756e693033304407756e693033304507756e +693033304607756e693033313007756e693033313107756e693033313207756e693033313307756e693033313407756e6930 +33313507756e693033313607756e693033313707756e693033313807756e693033313907756e693033314107756e69303331 +4207756e693033314307756e693033314407756e693033314507756e693033314607756e693033323007756e693033323107 +756e69303332320c646f7462656c6f77636f6d6207756e693033323407756e693033323507756e693033323607756e693033 +323707756e693033323807756e693033323907756e693033324107756e693033324207756e693033324307756e6930333244 +07756e693033324507756e693033324607756e693033333007756e693033333107756e693033333207756e69303333330775 +6e693033333407756e693033333507756e693033333607756e693033333707756e693033333807756e693033333907756e69 +3033334107756e693033334207756e693033334307756e693033334407756e693033334507756e693033334607756e693033 +343007756e693033343107756e693033343207756e693033343307756e693033343407756e693033343507756e6930333436 +07756e693033343707756e693033343807756e693033343907756e693033344107756e693033344207756e69303334430775 +6e693033344407756e693033344507756e693033344607756e693033353107756e693033353207756e693033353307756e69 +3033353707756e693033353807756e693033354107756e693033354307756e693033354407756e693033354507756e693033 +354607756e693033363007756e693033363107756e693033363207756e693033373007756e693033373107756e6930333732 +07756e693033373307756e693033373407756e693033373507756e693033373607756e693033373707756e69303337410775 +6e693033374207756e693033374307756e693033374407756e693033374505746f6e6f730d6469657265736973746f6e6f73 +0a416c706861746f6e6f7309616e6f74656c6569610c457073696c6f6e746f6e6f7308457461746f6e6f7309496f7461746f +6e6f730c4f6d6963726f6e746f6e6f730c557073696c6f6e746f6e6f730a4f6d656761746f6e6f7311696f74616469657265 +736973746f6e6f7305416c70686104426574610547616d6d6107756e693033393407457073696c6f6e045a65746103457461 +05546865746104496f7461054b61707061064c616d626461024d75024e75025869074f6d6963726f6e0250690352686f0553 +69676d610354617507557073696c6f6e0350686903436869035073690c496f746164696572657369730f557073696c6f6e64 +696572657369730a616c706861746f6e6f730c657073696c6f6e746f6e6f7308657461746f6e6f7309696f7461746f6e6f73 +14757073696c6f6e6469657265736973746f6e6f7305616c70686104626574610567616d6d610564656c746107657073696c +6f6e047a6574610365746105746865746104696f7461056b61707061066c616d62646107756e6930334243026e7502786907 +6f6d6963726f6e0372686f067369676d6131057369676d610374617507757073696c6f6e037068690363686903707369056f +6d6567610c696f746164696572657369730f757073696c6f6e64696572657369730c6f6d6963726f6e746f6e6f730c757073 +696c6f6e746f6e6f730a6f6d656761746f6e6f7307756e693033434607756e69303344300674686574613108557073696c6f +6e3107756e693033443307756e69303344340470686931066f6d6567613107756e693033443707756e693033443807756e69 +3033443907756e693033444107756e693033444207756e693033444307756e693033444407756e693033444507756e693033 +444607756e693033453007756e693033453107756e693033453207756e693033453307756e693033453407756e6930334535 +07756e693033453607756e693033453707756e693033453807756e693033453907756e693033454107756e69303345420775 +6e693033454307756e693033454407756e693033454507756e693033454607756e693033463007756e693033463107756e69 +3033463207756e693033463307756e693033463407756e693033463507756e693033463607756e693033463707756e693033 +463807756e693033463907756e693033464107756e693033464207756e693033464307756e693033464407756e6930334645 +07756e693033464607756e693034303007756e693034303107756e693034303207756e693034303307756e69303430340775 +6e693034303507756e693034303607756e693034303707756e693034303807756e693034303907756e693034304107756e69 +3034304207756e693034304307756e693034304407756e693034304507756e693034304607756e693034313007756e693034 +313107756e693034313207756e693034313307756e693034313407756e693034313507756e693034313607756e6930343137 +07756e693034313807756e693034313907756e693034314107756e693034314207756e693034314307756e69303431440775 +6e693034314507756e693034314607756e693034323007756e693034323107756e693034323207756e693034323307756e69 +3034323407756e693034323507756e693034323607756e693034323707756e693034323807756e693034323907756e693034 +324107756e693034324207756e693034324307756e693034324407756e693034324507756e693034324607756e6930343330 +07756e693034333107756e693034333207756e693034333307756e693034333407756e693034333507756e69303433360775 +6e693034333707756e693034333807756e693034333907756e693034334107756e693034334207756e693034334307756e69 +3034334407756e693034334507756e693034334607756e693034343007756e693034343107756e693034343207756e693034 +343307756e693034343407756e693034343507756e693034343607756e693034343707756e693034343807756e6930343439 +07756e693034344107756e693034344207756e693034344307756e693034344407756e693034344507756e69303434460775 +6e693034353007756e693034353107756e693034353207756e693034353307756e693034353407756e693034353507756e69 +3034353607756e693034353707756e693034353807756e693034353907756e693034354107756e693034354207756e693034 +354307756e693034354407756e693034354507756e693034354607756e693034363007756e693034363107756e6930343632 +07756e693034363307756e693034363407756e693034363507756e693034363607756e693034363707756e69303436380775 +6e693034363907756e693034364107756e693034364207756e693034364307756e693034364407756e693034364507756e69 +3034364607756e693034373007756e693034373107756e693034373207756e693034373307756e693034373407756e693034 +373507756e693034373607756e693034373707756e693034373807756e693034373907756e693034374107756e6930343742 +07756e693034374307756e693034374407756e693034374507756e693034374607756e693034383007756e69303438310775 +6e693034383207756e693034383307756e693034383407756e693034383507756e693034383607756e693034383707756e69 +3034383807756e693034383907756e693034384107756e693034384207756e693034384307756e693034384407756e693034 +384507756e693034384607756e693034393007756e693034393107756e693034393207756e693034393307756e6930343934 +07756e693034393507756e693034393607756e693034393707756e693034393807756e693034393907756e69303439410775 +6e693034394207756e693034394307756e693034394407756e693034394507756e693034394607756e693034413007756e69 +3034413107756e693034413207756e693034413307756e693034413407756e693034413507756e693034413607756e693034 +413707756e693034413807756e693034413907756e693034414107756e693034414207756e693034414307756e6930344144 +07756e693034414507756e693034414607756e693034423007756e693034423107756e693034423207756e69303442330775 +6e693034423407756e693034423507756e693034423607756e693034423707756e693034423807756e693034423907756e69 +3034424107756e693034424207756e693034424307756e693034424407756e693034424507756e693034424607756e693034 +433007756e693034433107756e693034433207756e693034433307756e693034433407756e693034433507756e6930344336 +07756e693034433707756e693034433807756e693034433907756e693034434107756e693034434207756e69303443430775 +6e693034434407756e693034434507756e693034434607756e693034443007756e693034443107756e693034443207756e69 +3034443307756e693034443407756e693034443507756e693034443607756e693034443707756e693034443807756e693034 +443907756e693034444107756e693034444207756e693034444307756e693034444407756e693034444507756e6930344446 +07756e693034453007756e693034453107756e693034453207756e693034453307756e693034453407756e69303445350775 +6e693034453607756e693034453707756e693034453807756e693034453907756e693034454107756e693034454207756e69 +3034454307756e693034454407756e693034454507756e693034454607756e693034463007756e693034463107756e693034 +463207756e693034463307756e693034463407756e693034463507756e693034463607756e693034463707756e6930344638 +07756e693034463907756e693034464107756e693034464207756e693034464307756e693034464407756e69303446450775 +6e693034464607756e693035303007756e693035303107756e693035303207756e693035303307756e693035303407756e69 +3035303507756e693035303607756e693035303707756e693035303807756e693035303907756e693035304107756e693035 +304207756e693035304307756e693035304407756e693035304507756e693035304607756e693035313007756e6930353131 +07756e693035313207756e693035313307756e693035313407756e693035313507756e693035313607756e69303531370775 +6e693035313807756e693035313907756e693035314107756e693035314207756e693035314307756e693035314407756e69 +3035314507756e693035314607756e693035323007756e693035323107756e693035323207756e693035323307756e693035 +323407756e693035323507756e693035333107756e693035333207756e693035333307756e693035333407756e6930353335 +07756e693035333607756e693035333707756e693035333807756e693035333907756e693035334107756e69303533420775 +6e693035334307756e693035334407756e693035334507756e693035334607756e693035343007756e693035343107756e69 +3035343207756e693035343307756e693035343407756e693035343507756e693035343607756e693035343707756e693035 +343807756e693035343907756e693035344107756e693035344207756e693035344307756e693035344407756e6930353445 +07756e693035344607756e693035353007756e693035353107756e693035353207756e693035353307756e69303535340775 +6e693035353507756e693035353607756e693035353907756e693035354107756e693035354207756e693035354307756e69 +3035354407756e693035354507756e693035354607756e693035363107756e693035363207756e693035363307756e693035 +363407756e693035363507756e693035363607756e693035363707756e693035363807756e693035363907756e6930353641 +07756e693035364207756e693035364307756e693035364407756e693035364507756e693035364607756e69303537300775 +6e693035373107756e693035373207756e693035373307756e693035373407756e693035373507756e693035373607756e69 +3035373707756e693035373807756e693035373907756e693035374107756e693035374207756e693035374307756e693035 +374407756e693035374507756e693035374607756e693035383007756e693035383107756e693035383207756e6930353833 +07756e693035383407756e693035383507756e693035383607756e693035383707756e693035383907756e69303538410775 +6e693035423007756e693035423107756e693035423207756e693035423307756e693035423407756e693035423507756e69 +3035423607756e693035423707756e693035423807756e693035423907756e693035424107756e693035424207756e693035 +424307756e693035424407756e693035424507756e693035424607756e693035433007756e693035433107756e6930354332 +07756e693035433307756e693035433607756e693035433707756e693035443007756e693035443107756e69303544320775 +6e693035443307756e693035443407756e693035443507756e693035443607756e693035443707756e693035443807756e69 +3035443907756e693035444107756e693035444207756e693035444307756e693035444407756e693035444507756e693035 +444607756e693035453007756e693035453107756e693035453207756e693035453307756e693035453407756e6930354535 +07756e693035453607756e693035453707756e693035453807756e693035453907756e693035454107756e69303546300775 +6e693035463107756e693035463207756e693035463307756e693035463407756e693036303607756e693036303707756e69 +3036303907756e693036304107756e693036304307756e693036313507756e693036314207756e693036314607756e693036 +323107756e693036323207756e693036323307756e693036323407756e693036323507756e693036323607756e6930363237 +07756e693036323807756e693036323907756e693036324107756e693036324207756e693036324307756e69303632440775 +6e693036324507756e693036324607756e693036333007756e693036333107756e693036333207756e693036333307756e69 +3036333407756e693036333507756e693036333607756e693036333707756e693036333807756e693036333907756e693036 +334107756e693036343007756e693036343107756e693036343207756e693036343307756e693036343407756e6930363435 +07756e693036343607756e693036343707756e693036343807756e693036343907756e693036344107756e69303634420775 +6e693036344307756e693036344407756e693036344507756e693036344607756e693036353007756e693036353107756e69 +3036353207756e693036353307756e693036353407756e693036353507756e693036353707756e693036354107756e693036 +363007756e693036363107756e693036363207756e693036363307756e693036363407756e693036363507756e6930363636 +07756e693036363707756e693036363807756e693036363907756e693036364107756e693036364207756e69303636430775 +6e693036364407756e693036364507756e693036364607756e693036373007756e693036373407756e693036373907756e69 +3036374107756e693036374207756e693036374307756e693036374407756e693036374507756e693036374607756e693036 +383007756e693036383107756e693036383207756e693036383307756e693036383407756e693036383507756e6930363836 +07756e693036383707756e693036383807756e693036383907756e693036384107756e693036384207756e69303638430775 +6e693036384407756e693036384507756e693036384607756e693036393007756e693036393107756e693036393207756e69 +3036393307756e693036393407756e693036393507756e693036393607756e693036393707756e693036393807756e693036 +393907756e693036394107756e693036394207756e693036394307756e693036394407756e693036394507756e6930363946 +07756e693036413007756e693036413107756e693036413207756e693036413307756e693036413407756e69303641350775 +6e693036413607756e693036413707756e693036413807756e693036413907756e693036414107756e693036414207756e69 +3036414307756e693036414407756e693036414507756e693036414607756e693036423007756e693036423107756e693036 +423207756e693036423307756e693036423407756e693036423507756e693036423607756e693036423707756e6930364238 +07756e693036423907756e693036424107756e693036424207756e693036424307756e693036424407756e69303642450775 +6e693036424607756e693036433607756e693036433707756e693036433807756e693036434207756e693036434307756e69 +3036434507756e693036443007756e693036443507756e693036463007756e693036463107756e693036463207756e693036 +463307756e693036463407756e693036463507756e693036463607756e693036463707756e693036463807756e6930364639 +07756e693037433007756e693037433107756e693037433207756e693037433307756e693037433407756e69303743350775 +6e693037433607756e693037433707756e693037433807756e693037433907756e693037434107756e693037434207756e69 +3037434307756e693037434407756e693037434507756e693037434607756e693037443007756e693037443107756e693037 +443207756e693037443307756e693037443407756e693037443507756e693037443607756e693037443707756e6930374438 +07756e693037443907756e693037444107756e693037444207756e693037444307756e693037444407756e69303744450775 +6e693037444607756e693037453007756e693037453107756e693037453207756e693037453307756e693037453407756e69 +3037453507756e693037453607756e693037453707756e693037454207756e693037454307756e693037454407756e693037 +454507756e693037454607756e693037463007756e693037463107756e693037463207756e693037463307756e6930374634 +07756e693037463507756e693037463807756e693037463907756e693037464107756e693045334607756e69304538310775 +6e693045383207756e693045383407756e693045383707756e693045383807756e693045384107756e693045384407756e69 +3045393407756e693045393507756e693045393607756e693045393707756e693045393907756e693045394107756e693045 +394207756e693045394307756e693045394407756e693045394507756e693045394607756e693045413107756e6930454132 +07756e693045413307756e693045413507756e693045413707756e693045414107756e693045414207756e69304541440775 +6e693045414507756e693045414607756e693045423007756e693045423107756e693045423207756e693045423307756e69 +3045423407756e693045423507756e693045423607756e693045423707756e693045423807756e693045423907756e693045 +424207756e693045424307756e693045424407756e693045433007756e693045433107756e693045433207756e6930454333 +07756e693045433407756e693045433607756e693045433807756e693045433907756e693045434107756e69304543420775 +6e693045434307756e693045434407756e693045443007756e693045443107756e693045443207756e693045443307756e69 +3045443407756e693045443507756e693045443607756e693045443707756e693045443807756e693045443907756e693045 +444307756e693045444407756e693130413007756e693130413107756e693130413207756e693130413307756e6931304134 +07756e693130413507756e693130413607756e693130413707756e693130413807756e693130413907756e69313041410775 +6e693130414207756e693130414307756e693130414407756e693130414507756e693130414607756e693130423007756e69 +3130423107756e693130423207756e693130423307756e693130423407756e693130423507756e693130423607756e693130 +423707756e693130423807756e693130423907756e693130424107756e693130424207756e693130424307756e6931304244 +07756e693130424507756e693130424607756e693130433007756e693130433107756e693130433207756e69313043330775 +6e693130433407756e693130433507756e693130443007756e693130443107756e693130443207756e693130443307756e69 +3130443407756e693130443507756e693130443607756e693130443707756e693130443807756e693130443907756e693130 +444107756e693130444207756e693130444307756e693130444407756e693130444507756e693130444607756e6931304530 +07756e693130453107756e693130453207756e693130453307756e693130453407756e693130453507756e69313045360775 +6e693130453707756e693130453807756e693130453907756e693130454107756e693130454207756e693130454307756e69 +3130454407756e693130454507756e693130454607756e693130463007756e693130463107756e693130463207756e693130 +463307756e693130463407756e693130463507756e693130463607756e693130463707756e693130463807756e6931304639 +07756e693130464107756e693130464207756e693130464307756e693134303107756e693134303207756e69313430330775 +6e693134303407756e693134303507756e693134303607756e693134303707756e693134303907756e693134304107756e69 +3134304207756e693134304307756e693134304407756e693134304507756e693134304607756e693134313007756e693134 +313107756e693134313207756e693134313307756e693134313407756e693134313507756e693134313607756e6931343137 +07756e693134313807756e693134313907756e693134314107756e693134314207756e693134314407756e69313431450775 +6e693134314607756e693134323007756e693134323107756e693134323207756e693134323307756e693134323407756e69 +3134323507756e693134323607756e693134323707756e693134323807756e693134323907756e693134324107756e693134 +324207756e6931343243077500><6e693134324407756e693134324507756e693134324607756e693134333007756e693134 +333107756e693134333207756e693134333307756e693134333407756e693134333507756e693134333707756e6931343338 +07756e693134333907756e693134334107756e693134334207756e693134334307756e693134334407756e69313433450775 +6e693134334607756e693134343007756e693134343107756e693134343207756e693134343307756e693134343407756e69 +3134343507756e693134343607756e693134343707756e693134343807756e693134343907756e693134344107756e693134 +344307756e693134344407756e693134344507756e693134344607756e693134353007756e693134353107756e6931343532 +07756e693134353407756e693134353507756e693134353607756e693134353707756e693134353807756e69313435390775 +6e693134354107756e693134354207756e693134354307756e693134354407756e693134354507756e693134354607756e69 +3134363007756e693134363107756e693134363207756e693134363307756e693134363407756e693134363507756e693134 +363607756e693134363707756e693134363807756e693134363907756e693134364107756e693134364207756e6931343643 +07756e693134364407756e693134364507756e693134364607756e693134373007756e693134373107756e69313437320775 +6e693134373307756e693134373407756e693134373507756e693134373607756e693134373707756e693134373807756e69 +3134373907756e693134374107756e693134374207756e693134374307756e693134374407756e693134374507756e693134 +374607756e693134383007756e693134383107756e693134383207756e693134383307756e693134383407756e6931343835 +07756e693134383607756e693134383707756e693134383807756e693134383907756e693134384107756e69313438420775 +6e693134384307756e693134384407756e693134384507756e693134384607756e693134393007756e693134393107756e69 +3134393207756e693134393307756e693134393407756e693134393507756e693134393607756e693134393707756e693134 +393807756e693134393907756e693134394107756e693134394207756e693134394307756e693134394407756e6931343945 +07756e693134394607756e693134413007756e693134413107756e693134413207756e693134413307756e69313441340775 +6e693134413507756e693134413607756e693134413707756e693134413807756e693134413907756e693134414107756e69 +3134414207756e693134414307756e693134414407756e693134414507756e693134414607756e693134423007756e693134 +423107756e693134423207756e693134423307756e693134423407756e693134423507756e693134423607756e6931344237 +07756e693134423807756e693134423907756e693134424107756e693134424207756e693134424307756e69313442440775 +6e693134433007756e693134433107756e693134433207756e693134433307756e693134433407756e693134433507756e69 +3134433607756e693134433707756e693134433807756e693134433907756e693134434107756e693134434207756e693134 +434307756e693134434407756e693134434507756e693134434607756e693134443007756e693134443107756e6931344432 +07756e693134443307756e693134443407756e693134443507756e693134443607756e693134443707756e69313444380775 +6e693134443907756e693134444107756e693134444207756e693134444307756e693134444407756e693134444507756e69 +3134444607756e693134453007756e693134453107756e693134453207756e693134453307756e693134453407756e693134 +453507756e693134453607756e693134453707756e693134453807756e693134453907756e693134454107756e6931344543 +07756e693134454407756e693134454507756e693134454607756e693134463007756e693134463107756e69313446320775 +6e693134463307756e693134463407756e693134463507756e693134463607756e693134463707756e693134463807756e69 +3134463907756e693134464107756e693134464207756e693134464307756e693134464407756e693134464507756e693134 +464607756e693135303007756e693135303107756e693135303207756e693135303307756e693135303407756e6931353035 +07756e693135303607756e693135303707756e693135313007756e693135313107756e693135313207756e69313531330775 +6e693135313407756e693135313507756e693135313607756e693135313707756e693135313807756e693135313907756e69 +3135314107756e693135314207756e693135314307756e693135314407756e693135314507756e693135314607756e693135 +323007756e693135323107756e693135323207756e693135323307756e693135323407756e693135323507756e6931353236 +07756e693135323707756e693135323807756e693135323907756e693135324107756e693135324207756e69313532430775 +6e693135324407756e693135324507756e693135324607756e693135333007756e693135333107756e693135333207756e69 +3135333307756e693135333407756e693135333507756e693135333607756e693135333707756e693135333807756e693135 +333907756e693135334107756e693135334207756e693135334307756e693135334407756e693135334507756e6931353430 +07756e693135343107756e693135343207756e693135343307756e693135343407756e693135343507756e69313534360775 +6e693135343707756e693135343807756e693135343907756e693135344107756e693135344207756e693135344307756e69 +3135344407756e693135344507756e693135344607756e693135353007756e693135353207756e693135353307756e693135 +353407756e693135353507756e693135353607756e693135353707756e693135353807756e693135353907756e6931353541 +07756e693135354207756e693135354307756e693135354407756e693135354507756e693135354607756e69313536300775 +6e693135363107756e693135363207756e693135363307756e693135363407756e693135363507756e693135363607756e69 +3135363707756e693135363807756e693135363907756e693135364107756e693135373407756e693135373507756e693135 +373607756e693135373707756e693135373807756e693135373907756e693135374107756e693135374207756e6931353743 +07756e693135374407756e693135374507756e693135374607756e693135383007756e693135383107756e69313538320775 +6e693135383307756e693135383407756e693135383507756e693135384107756e693135384207756e693135384307756e69 +3135384407756e693135384507756e693135384607756e693135393007756e693135393107756e693135393207756e693135 +393307756e693135393407756e693135393507756e693135393607756e693135413007756e693135413107756e6931354132 +07756e693135413307756e693135413407756e693135413507756e693135413607756e693135413707756e69313541380775 +6e693135413907756e693135414107756e693135414207756e693135414307756e693135414407756e693135414507756e69 +3135414607756e693135444507756e693135453107756e693136343607756e693136343707756e693136364507756e693136 +364607756e693136373007756e693136373107756e693136373207756e693136373307756e693136373407756e6931363735 +07756e693136373607756e693136383007756e693136383107756e693136383207756e693136383307756e69313638340775 +6e693136383507756e693136383607756e693136383707756e693136383807756e693136383907756e693136384107756e69 +3136384207756e693136384307756e693136384407756e693136384507756e693136384607756e693136393007756e693136 +393107756e693136393207756e693136393307756e693136393407756e693136393507756e693136393607756e6931363937 +07756e693136393807756e693136393907756e693136394107756e693136394207756e693136394307756e69314430300775 +6e693144303107756e693144303207756e693144303307756e693144303407756e693144303507756e693144303607756e69 +3144303707756e693144303807756e693144303907756e693144304107756e693144304207756e693144304307756e693144 +304407756e693144304507756e693144304607756e693144313007756e693144313107756e693144313207756e6931443133 +07756e693144313407756e693144313607756e693144313707756e693144313807756e693144313907756e69314431410775 +6e693144314207756e693144314307756e693144314407756e693144314507756e693144314607756e693144323007756e69 +3144323107756e693144323207756e693144323307756e693144323607756e693144323707756e693144323807756e693144 +323907756e693144324107756e693144324207756e693144324307756e693144324407756e693144324507756e6931443330 +07756e693144333107756e693144333207756e693144333307756e693144333407756e693144333507756e69314433360775 +6e693144333707756e693144333807756e693144333907756e693144334107756e693144334207756e693144334307756e69 +3144334407756e693144334507756e693144334607756e693144343007756e693144343107756e693144343207756e693144 +343307756e693144343407756e693144343507756e693144343607756e693144343707756e693144343807756e6931443439 +07756e693144344107756e693144344207756e693144344307756e693144344407756e693144344507756e69314434460775 +6e693144353007756e693144353107756e693144353207756e693144353307756e693144353407756e693144353507756e69 +3144353607756e693144353707756e693144353807756e693144353907756e693144354107756e693144354207756e693144 +354407756e693144354507756e693144354607756e693144363007756e693144363107756e693144363207756e6931443633 +07756e693144363407756e693144363507756e693144363607756e693144363707756e693144363807756e69314436390775 +6e693144364107756e693144373707756e693144373807756e693144374207756e693144374407756e693144383507756e69 +3144394207756e693144394307756e693144394407756e693144394507756e693144394607756e693144413007756e693144 +413107756e693144413207756e693144413307756e693144413407756e693144413507756e693144413607756e6931444137 +07756e693144413807756e693144413907756e693144414107756e693144414207756e693144414307756e69314441440775 +6e693144414507756e693144414607756e693144423007756e693144423107756e693144423207756e693144423307756e69 +3144423407756e693144423507756e693144423607756e693144423707756e693144423807756e693144423907756e693144 +424107756e693144424207756e693144424307756e693144424407756e693144424507756e693144424607756e6931444334 +07756e693144433507756e693144433607756e693144433707756e693144433807756e693144433907756e69314530300775 +6e693145303107756e693145303207756e693145303307756e693145303407756e693145303507756e693145303607756e69 +3145303707756e693145303807756e693145303907756e693145304107756e693145304207756e693145304307756e693145 +304407756e693145304507756e693145304607756e693145313007756e693145313107756e693145313207756e6931453133 +07756e693145313407756e693145313507756e693145313607756e693145313707756e693145313807756e69314531390775 +6e693145314107756e693145314207756e693145314307756e693145314407756e693145314507756e693145314607756e69 +3145323007756e693145323107756e693145323207756e693145323307756e693145323407756e693145323507756e693145 +323607756e693145323707756e693145323807756e693145323907756e693145324107756e693145324207756e6931453243 +07756e693145324407756e693145324507756e693145324607756e693145333007756e693145333107756e69314533320775 +6e693145333307756e693145333407756e693145333507756e693145333607756e693145333707756e693145333807756e69 +3145333907756e693145334107756e693145334207756e693145334307756e693145334407756e693145334507756e693145 +334607756e693145343007756e693145343107756e693145343207756e693145343307756e693145343407756e6931453435 +07756e693145343607756e693145343707756e693145343807756e693145343907756e693145344107756e69314534420775 +6e693145344307756e693145344407756e693145344507756e693145344607756e693145353007756e693145353107756e69 +3145353207756e693145353307756e693145353407756e693145353507756e693145353607756e693145353707756e693145 +353807756e693145353907756e693145354107756e693145354207756e693145354307756e693145354407756e6931453545 +07756e693145354607756e693145363007756e693145363107756e693145363207756e693145363307756e69314536340775 +6e693145363507756e693145363607756e693145363707756e693145363807756e693145363907756e693145364107756e69 +3145364207756e693145364307756e693145364407756e693145364507756e693145364607756e693145373007756e693145 +373107756e693145373207756e693145373307756e693145373407756e693145373507756e693145373607756e6931453737 +07756e693145373807756e693145373907756e693145374107756e693145374207756e693145374307756e69314537440775 +6e693145374507756e6931453746065767726176650677677261766506576163757465067761637574650957646965726573 +69730977646965726573697307756e693145383607756e693145383707756e693145383807756e693145383907756e693145 +384107756e693145384207756e693145384307756e693145384407756e693145384507756e693145384607756e6931453930 +07756e693145393107756e693145393207756e693145393307756e693145393407756e693145393507756e69314539360775 +6e693145393707756e693145393807756e693145393907756e693145394107756e693145394207756e693145394307756e69 +3145394407756e693145394507756e693145394607756e693145413007756e693145413107756e693145413207756e693145 +413307756e693145413407756e693145413507756e693145413607756e693145413707756e693145413807756e6931454139 +07756e693145414107756e693145414207756e693145414307756e693145414407756e693145414507756e69314541460775 +6e693145423007756e693145423107756e693145423207756e693145423307756e693145423407756e693145423507756e69 +3145423607756e693145423707756e693145423807756e693145423907756e693145424107756e693145424207756e693145 +424307756e693145424407756e693145424507756e693145424607756e693145433007756e693145433107756e6931454332 +07756e693145433307756e693145433407756e693145433507756e693145433607756e693145433707756e69314543380775 +6e693145433907756e693145434107756e693145434207756e693145434307756e693145434407756e693145434507756e69 +3145434607756e693145443007756e693145443107756e693145443207756e693145443307756e693145443407756e693145 +443507756e693145443607756e693145443707756e693145443807756e693145443907756e693145444107756e6931454442 +07756e693145444307756e693145444407756e693145444507756e693145444607756e693145453007756e69314545310775 +6e693145453207756e693145453307756e693145453407756e693145453507756e693145453607756e693145453707756e69 +3145453807756e693145453907756e693145454107756e693145454207756e693145454307756e693145454407756e693145 +454507756e693145454607756e693145463007756e6931454631065967726176650679677261766507756e69314546340775 +6e693145463507756e693145463607756e693145463707756e693145463807756e693145463907756e693145464107756e69 +3145464207756e693146303007756e693146303107756e693146303207756e693146303307756e693146303407756e693146 +303507756e693146303607756e693146303707756e693146303807756e693146303907756e693146304107756e6931463042 +07756e693146304307756e693146304407756e693146304507756e693146304607756e693146313007756e69314631310775 +6e693146313207756e693146313307756e693146313407756e693146313507756e693146313807756e693146313907756e69 +3146314107756e693146314207756e693146314307756e693146314407756e693146323007756e693146323107756e693146 +323207756e693146323307756e693146323407756e693146323507756e693146323607756e693146323707756e6931463238 +07756e693146323907756e693146324107756e693146324207756e693146324307756e693146324407756e69314632450775 +6e693146324607756e693146333007756e693146333107756e693146333207756e693146333307756e693146333407756e69 +3146333507756e693146333607756e693146333707756e693146333807756e693146333907756e693146334107756e693146 +334207756e693146334307756e693146334407756e693146334507756e693146334607756e693146343007756e6931463431 +07756e693146343207756e693146343307756e693146343407756e693146343507756e693146343807756e69314634390775 +6e693146344107756e693146344207756e693146344307756e693146344407756e693146353007756e693146353107756e69 +3146353207756e693146353307756e693146353407756e693146353507756e693146353607756e693146353707756e693146 +353907756e693146354207756e693146354407756e693146354607756e693146363007756e693146363107756e6931463632 +07756e693146363307756e693146363407756e693146363507756e693146363607756e693146363707756e69314636380775 +6e693146363907756e693146364107756e693146364207756e693146364307756e693146364407756e693146364507756e69 +3146364607756e693146373007756e693146373107756e693146373207756e693146373307756e693146373407756e693146 +373507756e693146373607756e693146373707756e693146373807756e693146373907756e693146374107756e6931463742 +07756e693146374307756e693146374407756e693146383007756e693146383107756e693146383207756e69314638330775 +6e693146383407756e693146383507756e693146383607756e693146383707756e693146383807756e693146383907756e69 +3146384107756e693146384207756e693146384307756e693146384407756e693146384507756e693146384607756e693146 +393007756e693146393107756e693146393207756e693146393307756e693146393407756e693146393507756e6931463936 +07756e693146393707756e693146393807756e693146393907756e693146394107756e693146394207756e69314639430775 +6e693146394407756e693146394507756e693146394607756e693146413007756e693146413107756e693146413207756e69 +3146413307756e693146413407756e693146413507756e693146413607756e693146413707756e693146413807756e693146 +413907756e693146414107756e693146414207756e693146414307756e693146414407756e693146414507756e6931464146 +07756e693146423007756e693146423107756e693146423207756e693146423307756e693146423407756e69314642360775 +6e693146423707756e693146423807756e693146423907756e693146424107756e693146424207756e693146424307756e69 +3146424407756e693146424507756e693146424607756e693146433007756e693146433107756e693146433207756e693146 +433307756e693146433407756e693146433607756e693146433707756e693146433807756e693146433907756e6931464341 +07756e693146434207756e693146434307756e693146434407756e693146434507756e693146434607756e69314644300775 +6e693146443107756e693146443207756e693146443307756e693146443607756e693146443707756e693146443807756e69 +3146443907756e693146444107756e693146444207756e693146444407756e693146444507756e693146444607756e693146 +453007756e693146453107756e693146453207756e693146453307756e693146453407756e693146453507756e6931464536 +07756e693146453707756e693146453807756e693146453907756e693146454107756e693146454207756e69314645430775 +6e693146454407756e693146454507756e693146454607756e693146463207756e693146463307756e693146463407756e69 +3146463607756e693146463707756e693146463807756e693146463907756e693146464107756e693146464207756e693146 +464307756e693146464407756e693146464507756e693230303007756e693230303107756e693230303207756e6932303033 +07756e693230303407756e693230303507756e693230303607756e693230303707756e693230303807756e69323030390775 +6e693230304107756e693230304207756e693230304307756e693230304407756e693230304507756e693230304607756e69 +3230313007756e69323031310a6669677572656461736807756e693230313507756e69323031360d756e64657273636f7265 +64626c0d71756f7465726576657273656407756e693230314607756e69323032330e6f6e65646f74656e6c65616465720e74 +776f646f74656e6c656164657207756e693230323707756e693230323807756e693230323907756e693230324107756e6932 +30324207756e693230324307756e693230324407756e693230324507756e693230324607756e6932303331066d696e757465 +067365636f6e6407756e693230333407756e693230333507756e693230333607756e693230333707756e693230333807756e +6932303342096578636c616d64626c07756e693230334407756e693230334507756e693230334607756e693230343007756e +693230343107756e693230343207756e693230343307756e693230343507756e693230343607756e693230343707756e6932 +30343807756e693230343907756e693230344107756e693230344207756e693230344307756e693230344407756e69323034 +4507756e693230344607756e693230353007756e693230353107756e693230353207756e693230353307756e693230353407 +756e693230353507756e693230353607756e693230353707756e693230353807756e693230353907756e693230354107756e +693230354207756e693230354307756e693230354407756e693230354507756e693230354607756e693230363007756e6932 +30363107756e693230363207756e693230363307756e693230363407756e693230364107756e693230364207756e69323036 +4307756e693230364407756e693230364507756e693230364607756e693230373007756e693230373107756e693230373407 +756e693230373507756e693230373607756e693230373707756e693230373807756e693230373907756e693230374107756e +693230374207756e693230374307756e693230374407756e693230374507756e693230374607756e693230383007756e6932 +30383107756e693230383207756e693230383307756e693230383407756e693230383507756e693230383607756e69323038 +3707756e693230383807756e693230383907756e693230384107756e693230384207756e693230384307756e693230384407 +756e693230384507756e693230393007756e693230393107756e693230393207756e693230393307756e693230393407756e +693230393507756e693230393607756e693230393707756e693230393807756e693230393907756e693230394107756e6932 +30394207756e693230394307756e69323041300d636f6c6f6e6d6f6e657461727907756e6932304132046c69726107756e69 +3230413507756e69323041360670657365746107756e693230413807756e693230413907756e693230414104646f6e670445 +75726f07756e693230414407756e693230414507756e693230414607756e693230423007756e693230423107756e69323042 +3207756e693230423307756e693230423407756e693230423507756e693230423807756e693230423907756e693230424107 +756e693230424407756e693230443007756e693230443107756e693230443607756e693230443707756e693230444207756e +693230444307756e693230453107756e693231303007756e693231303107756e693231303207756e693231303307756e6932 +31303407756e693231303507756e693231303607756e693231303707756e693231303807756e693231303907756e69323130 +4207756e693231304307756e693231304407756e693231304507756e693231304607756e693231313008496672616b747572 +07756e693231313207756e693231313307756e693231313407756e693231313507756e693231313607756e69323131370b77 +6569657273747261737307756e693231313907756e693231314107756e693231314208526672616b74757207756e69323131 +440c707265736372697074696f6e07756e693231314607756e693231323007756e693231323107756e693231323307756e69 +3231323407756e693231323507756e693231323607756e693231323707756e693231323807756e693231323907756e693231 +324107756e693231324207756e693231324307756e693231324409657374696d6174656407756e693231324607756e693231 +333007756e693231333107756e693231333207756e693231333307756e693231333405616c65706807756e69323133360775 +6e693231333707756e693231333807756e693231333907756e693231334107756e693231334207756e693231334307756e69 +3231334407756e693231334507756e693231334607756e693231343007756e693231343107756e693231343207756e693231 +343307756e693231343407756e693231343507756e693231343607756e693231343707756e693231343807756e6932313439 +07756e693231344207756e693231344507756e693231353007756e693231353107756e6932313532086f6e65746869726409 +74776f74686972647307756e693231353507756e693231353607756e693231353707756e693231353807756e693231353907 +756e6932313541096f6e656569676874680c7468726565656967687468730b66697665656967687468730c736576656e6569 +676874687307756e693231354607756e693231363007756e693231363107756e693231363207756e693231363307756e6932 +31363407756e693231363507756e693231363607756e693231363707756e693231363807756e693231363907756e69323136 +4107756e693231364207756e693231364307756e693231364407756e693231364507756e693231364607756e693231373007 +756e693231373107756e693231373207756e693231373307756e693231373407756e693231373507756e693231373607756e +693231373707756e693231373807756e693231373907756e693231374107756e693231374207756e693231374307756e6932 +31374407756e693231374507756e693231374607756e693231383007756e693231383107756e693231383207756e69323138 +3307756e693231383407756e693231383507756e6932313839096172726f776c656674076172726f7775700a6172726f7772 +69676874096172726f77646f776e096172726f77626f7468096172726f777570646e07756e693231393607756e6932313937 +07756e693231393807756e693231393907756e693231394107756e693231394207756e693231394307756e69323139440775 +6e693231394507756e693231394607756e693231413007756e693231413107756e693231413207756e693231413307756e69 +3231413407756e693231413507756e693231413607756e69323141370c6172726f777570646e62736507756e693231413907 +756e693231414107756e693231414207756e693231414307756e693231414407756e693231414507756e693231414607756e +693231423007756e693231423107756e693231423207756e693231423307756e69323142340e636172726961676572657475 +726e07756e693231423607756e693231423707756e693231423807756e693231423907756e693231424107756e6932314242 +07756e693231424307756e693231424407756e693231424507756e693231424607756e693231433007756e69323143310775 +6e693231433207756e693231433307756e693231433407756e693231433507756e693231433607756e693231433707756e69 +3231433807756e693231433907756e693231434107756e693231434207756e693231434307756e693231434407756e693231 +434507756e69323143460c6172726f7764626c6c6566740a6172726f7764626c75700d6172726f7764626c72696768740c61 +72726f7764626c646f776e0c6172726f7764626c626f746807756e693231443507756e693231443607756e69323144370775 +6e693231443807756e693231443907756e693231444107756e693231444207756e693231444307756e693231444407756e69 +3231444507756e693231444607756e693231453007756e693231453107756e693231453207756e693231453307756e693231 +453407756e693231453507756e693231453607756e693231453707756e693231453807756e693231453907756e6932314541 +07756e693231454207756e693231454307756e693231454407756e693231454507756e693231454607756e69323146300775 +6e693231463107756e693231463207756e693231463307756e693231463407756e693231463507756e693231463607756e69 +3231463707756e693231463807756e693231463907756e693231464107756e693231464207756e693231464307756e693231 +464407756e693231464507756e693231464609756e6976657273616c07756e69323230310b6578697374656e7469616c0775 +6e693232303408656d707479736574086772616469656e7407656c656d656e740a6e6f74656c656d656e7407756e69323230 +4108737563687468617407756e693232304307756e693232304407756e693232304507756e693232313007756e6932323133 +07756e693232313407756e693232313507756e69323231360c617374657269736b6d61746807756e693232313807756e6932 +32313907756e693232314207756e69323231430c70726f706f7274696f6e616c0a6f7274686f676f6e616c05616e676c6507 +756e693232323107756e693232323207756e693232323307756e693232323407756e693232323507756e69323232360a6c6f +676963616c616e64096c6f676963616c6f720c696e74657273656374696f6e05756e696f6e07756e693232324307756e6932 +32324407756e693232324507756e693232324607756e693232333007756e693232333107756e693232333207756e69323233 +33097468657265666f726507756e693232333507756e693232333607756e693232333707756e693232333807756e69323233 +3907756e693232334107756e69323233420773696d696c617207756e693232334407756e693232334507756e693232334607 +756e693232343007756e693232343107756e693232343207756e693232343307756e693232343409636f6e677275656e7407 +756e693232343607756e693232343707756e693232343907756e693232344107756e693232344207756e693232344307756e +693232344407756e693232344507756e693232344607756e693232353007756e693232353107756e693232353207756e6932 +32353307756e693232353407756e693232353507756e693232353607756e693232353707756e693232353807756e69323235 +3907756e693232354107756e693232354207756e693232354307756e693232354407756e693232354507756e69323235460b +6571756976616c656e636507756e693232363207756e693232363307756e693232363607756e693232363707756e69323236 +3807756e693232363907756e693232364107756e693232364207756e693232364307756e693232364407756e693232364507 +756e693232364607756e693232373007756e693232373107756e693232373207756e693232373307756e693232373407756e +693232373507756e693232373607756e693232373707756e693232373807756e693232373907756e693232374107756e6932 +32374207756e693232374307756e693232374407756e693232374507756e693232374607756e693232383007756e69323238 +310c70726f7065727375627365740e70726f7065727375706572736574096e6f7473756273657407756e69323238350c7265 +666c65787375627365740e7265666c6578737570657273657407756e693232383807756e693232383907756e693232384107 +756e693232384207756e693232384307756e693232384407756e693232384507756e693232384607756e693232393007756e +693232393107756e693232393207756e693232393307756e69323239340a636972636c65706c757307756e69323239360e63 +6972636c656d756c7469706c7907756e693232393807756e693232393907756e693232394107756e693232394207756e6932 +32394307756e693232394407756e693232394507756e693232394607756e693232413007756e693232413107756e69323241 +3207756e693232413307756e69323241340d70657270656e646963756c617207756e693232413607756e693232413707756e +693232413807756e693232413907756e693232414107756e693232414207756e693232414307756e693232414407756e6932 +32414507756e693232414607756e693232423007756e693232423107756e693232423207756e693232423307756e69323242 +3407756e693232423507756e693232423607756e693232423707756e693232423807756e693232423907756e693232424107 +756e693232424207756e693232424307756e693232424407756e693232424507756e693232424607756e693232433007756e +693232433107756e693232433207756e693232433307756e693232433407646f746d61746807756e693232433607756e6932 +32433707756e693232433807756e693232433907756e693232434107756e693232434207756e693232434307756e69323243 +4407756e693232434507756e693232434607756e693232443007756e693232443107756e693232443207756e693232443307 +756e693232443407756e693232443507756e693232443607756e693232443707756e693232443807756e693232443907756e +693232444107756e693232444207756e693232444307756e693232444407756e693232444507756e693232444607756e6932 +32453007756e693232453107756e693232453207756e693232453307756e693232453407756e693232453507756e69323245 +3607756e693232453707756e693232453807756e693232453907756e693232454107756e693232454207756e693232454307 +756e693232454407756e693232454507756e693232454607756e693232463007756e693232463107756e693232463207756e +693232463307756e693232463407756e693232463507756e693232463607756e693232463707756e693232463807756e6932 +32463907756e693232464107756e693232464207756e693232464307756e693232464407756e693232464507756e69323246 +4607756e693233303007756e693233303105686f75736507756e693233303307756e693233303407756e693233303507756e +693233303607756e693233303707756e693233303807756e693233303907756e693233304107756e693233304207756e6932 +33304307756e693233304407756e693233304507756e69323330460d7265766c6f676963616c6e6f7407756e693233313107 +756e693233313807756e693233313907756e693233314307756e693233314407756e693233314507756e69323331460a696e +74656772616c74700a696e74656772616c627407756e693233323407756e693233323507756e693233323607756e69323332 +3707756e693233323807756e693233324207756e693233324307756e693233373307756e693233373407756e693233373507 +756e693233374107756e693233374407756e693233383707756e693233393407756e693233394207756e693233394307756e +693233394407756e693233394507756e693233394607756e693233413007756e693233413107756e693233413207756e6932 +33413307756e693233413407756e693233413507756e693233413607756e693233413707756e693233413807756e69323341 +3907756e693233414107756e693233414207756e693233414307756e693233414407756e693233414507756e693233434507 +756e693233434607756e693233453307756e693233453507756e693233453807756e693234323207756e693234323307756e +693234363007756e693234363107756e693234363207756e693234363307756e693234363407756e693234363507756e6932 +34363607756e693234363707756e693234363807756e693234363908534631303030303007756e6932353031085346313130 +30303007756e693235303307756e693235303407756e693235303507756e693235303607756e693235303707756e69323530 +3807756e693235303907756e693235304107756e693235304208534630313030303007756e693235304407756e6932353045 +07756e693235304608534630333030303007756e693235313107756e693235313207756e6932353133085346303230303030 +07756e693235313507756e693235313607756e693235313708534630343030303007756e693235313907756e693235314107 +756e693235314208534630383030303007756e693235314407756e693235314507756e693235314607756e69323532300775 +6e693235323107756e693235323207756e693235323308534630393030303007756e693235323507756e693235323607756e +693235323707756e693235323807756e693235323907756e693235324107756e693235324208534630363030303007756e69 +3235324407756e693235324507756e693235324607756e693235333007756e693235333107756e693235333207756e693235 +333308534630373030303007756e693235333507756e693235333607756e693235333707756e693235333807756e69323533 +3907756e693235334107756e693235334208534630353030303007756e693235334407756e693235334507756e6932353346 +07756e693235343007756e693235343107756e693235343207756e693235343307756e693235343407756e69323534350775 +6e693235343607756e693235343707756e693235343807756e693235343907756e693235344107756e693235344207756e69 +3235344307756e693235344407756e693235344507756e693235344608534634333030303008534632343030303008534635 +3130303030085346353230303030085346333930303030085346323230303030085346323130303030085346323530303030 +0853463530303030300853463439303030300853463338303030300853463238303030300853463237303030300853463236 +3030303008534633363030303008534633373030303008534634323030303008534631393030303008534632303030303008 +5346323330303030085346343730303030085346343830303030085346343130303030085346343530303030085346343630 +30303008534634303030303008534635343030303008534635333030303008534634343030303007756e693235364407756e +693235364507756e693235364607756e693235373007756e693235373107756e693235373207756e693235373307756e6932 +35373407756e693235373507756e693235373607756e693235373707756e693235373807756e693235373907756e69323537 +4107756e693235374207756e693235374307756e693235374407756e693235374507756e6932353746077570626c6f636b07 +756e693235383107756e693235383207756e693235383307646e626c6f636b07756e693235383507756e693235383607756e +693235383705626c6f636b07756e693235383907756e693235384107756e6932353842076c66626c6f636b07756e69323538 +4407756e693235384507756e6932353846077274626c6f636b076c74736861646505736861646507646b736861646507756e +693235393407756e693235393507756e693235393607756e693235393707756e693235393807756e693235393907756e6932 +35394107756e693235394207756e693235394307756e693235394407756e693235394507756e69323539460966696c6c6564 +626f780648323230373307756e693235413207756e693235413307756e693235413407756e693235413507756e6932354136 +07756e693235413707756e693235413807756e693235413906483138353433064831383535310a66696c6c65647265637407 +756e693235414407756e693235414507756e693235414607756e693235423007756e6932354231077472696167757007756e +693235423307756e693235423407756e693235423507756e693235423607756e693235423707756e693235423807756e6932 +354239077472696167727407756e6932354242077472696167646e07756e693235424407756e693235424507756e69323542 +4607756e693235433007756e693235433107756e693235433207756e69323543330774726961676c6607756e693235433507 +756e693235433607756e693235433707756e693235433807756e693235433906636972636c6507756e693235434307756e69 +3235434407756e69323543450648313835333307756e693235443007756e693235443107756e693235443207756e69323544 +3307756e693235443407756e693235443507756e693235443607756e693235443709696e7662756c6c657409696e76636972 +636c6507756e693235444107756e693235444207756e693235444307756e693235444407756e693235444507756e69323544 +4607756e693235453007756e693235453107756e693235453207756e693235453307756e693235453407756e69323545350a +6f70656e62756c6c657407756e693235453707756e693235453807756e693235453907756e693235454107756e6932354542 +07756e693235454307756e693235454407756e693235454507756e693235454607756e693235463007756e69323546310775 +6e693235463207756e693235463307756e693235463407756e693235463507756e693235463607756e693235463707756e69 +3235463807756e693235463907756e693235464107756e693235464207756e693235464307756e693235464407756e693235 +464507756e693235464607756e693236303007756e693236303107756e693236303207756e693236303307756e6932363034 +07756e693236303507756e693236303607756e693236303707756e693236303807756e693236303907756e69323630410775 +6e693236304207756e693236304307756e693236304407756e693236304507756e693236304607756e693236313007756e69 +3236313107756e693236313207756e693236313307756e693236313407756e693236313507756e693236313607756e693236 +313707756e693236313807756e693236313907756e693236314107756e693236314207756e693236314307756e6932363144 +07756e693236314507756e693236314607756e693236323007756e693236323107756e693236323207756e69323632330775 +6e693236323407756e693236323507756e693236323607756e693236323707756e693236323807756e693236323907756e69 +3236324107756e693236324207756e693236324307756e693236324407756e693236324507756e693236324607756e693236 +333007756e693236333107756e693236333207756e693236333307756e693236333407756e693236333507756e6932363336 +07756e693236333707756e693236333807756e693236333909736d696c65666163650c696e76736d696c6566616365037375 +6e07756e693236334407756e693236334507756e69323633460666656d616c6507756e6932363431046d616c6507756e6932 +36343307756e693236343407756e693236343507756e693236343607756e693236343707756e693236343807756e69323634 +3907756e693236344107756e693236344207756e693236344307756e693236344407756e693236344507756e693236344607 +756e693236353007756e693236353107756e693236353207756e693236353307756e693236353407756e693236353507756e +693236353607756e693236353707756e693236353807756e693236353907756e693236354107756e693236354207756e6932 +36354307756e693236354407756e693236354507756e693236354605737061646507756e693236363107756e693236363204 +636c756207756e6932363634056865617274076469616d6f6e6407756e693236363707756e693236363807756e6932363639 +0b6d75736963616c6e6f74650e6d75736963616c6e6f746564626c07756e693236364307756e693236364407756e69323636 +4507756e693236364607756e693236373007756e693236373107756e693236373207756e693236373307756e693236373407 +756e693236373507756e693236373607756e693236373707756e693236373807756e693236373907756e693236374107756e +693236374207756e693236374307756e693236374407756e693236374507756e693236374607756e693236383007756e6932 +36383107756e693236383207756e693236383307756e693236383407756e693236383507756e693236383607756e69323638 +3707756e693236383807756e693236383907756e693236384107756e693236384207756e693236384307756e693236384407 +756e693236384507756e693236384607756e693236393007756e693236393107756e693236393207756e693236393307756e +693236393407756e693236393507756e693236393607756e693236393707756e693236393807756e693236393907756e6932 +36394107756e693236394207756e693236394307756e693236394507756e693236394607756e693236413007756e69323641 +3107756e693236413207756e693236413307756e693236413407756e693236413507756e693236413607756e693236413707 +756e693236413807756e693236413907756e693236414107756e693236414207756e693236414307756e693236414407756e +693236414507756e693236414607756e693236423007756e693236423107756e693236423207756e693236423307756e6932 +36423407756e693236423507756e693236423607756e693236423707756e693236423807756e693236433007756e69323643 +3107756e693236433207756e693236433307756e693236453207756e693237303107756e693237303207756e693237303307 +756e693237303407756e693237303607756e693237303707756e693237303807756e693237303907756e693237304307756e +693237304407756e693237304507756e693237304607756e693237313007756e693237313107756e693237313207756e6932 +37313307756e693237313407756e693237313507756e693237313607756e693237313707756e693237313807756e69323731 +3907756e693237314107756e693237314207756e693237314307756e693237314407756e693237314507756e693237314607 +756e693237323007756e693237323107756e693237323207756e693237323307756e693237323407756e693237323507756e +693237323607756e693237323707756e693237323907756e693237324107756e693237324207756e693237324307756e6932 +37324407756e693237324507756e693237324607756e693237333007756e693237333107756e693237333207756e69323733 +3307756e693237333407756e693237333507756e693237333607756e693237333707756e693237333807756e693237333907 +756e693237334107756e693237334207756e693237334307756e693237334407756e693237334507756e693237334607756e +693237343007756e693237343107756e693237343207756e693237343307756e693237343407756e693237343507756e6932 +37343607756e693237343707756e693237343807756e693237343907756e693237344107756e693237344207756e69323734 +4407756e693237344607756e693237353007756e693237353107756e693237353207756e693237353607756e693237353807 +756e693237353907756e693237354107756e693237354207756e693237354307756e693237354407756e693237354507756e +693237363107756e693237363207756e693237363307756e693237363407756e693237363507756e693237363607756e6932 +37363707756e693237363807756e693237363907756e693237364107756e693237364207756e693237364307756e69323736 +4407756e693237364507756e693237364607756e693237373007756e693237373107756e693237373207756e693237373307 +756e693237373407756e693237373507756e693237373607756e693237373707756e693237373807756e693237373907756e +693237374107756e693237374207756e693237374307756e693237374407756e693237374507756e693237374607756e6932 +37383007756e693237383107756e693237383207756e693237383307756e693237383407756e693237383507756e69323738 +3607756e693237383707756e693237383807756e693237383907756e693237384107756e693237384207756e693237384307 +756e693237384407756e693237384507756e693237384607756e693237393007756e693237393107756e693237393207756e +693237393307756e693237393407756e693237393807756e693237393907756e693237394107756e693237394207756e6932 +37394307756e693237394407756e693237394507756e693237394607756e693237413007756e693237413107756e69323741 +3207756e693237413307756e693237413407756e693237413507756e693237413607756e693237413707756e693237413807 +756e693237413907756e693237414107756e693237414207756e693237414307756e693237414407756e693237414507756e +693237414607756e693237423107756e693237423207756e693237423307756e693237423407756e693237423507756e6932 +37423607756e693237423707756e693237423807756e693237423907756e693237424107756e693237424207756e69323742 +4307756e693237424407756e693237424507756e693237433507756e693237433607756e693237453007756e693237453607 +756e693237453707756e693237453807756e693237453907756e693237454107756e693237454207756e693237463007756e +693237463107756e693237463207756e693237463307756e693237463407756e693237463507756e693237463607756e6932 +37463707756e693237463807756e693237463907756e693237464107756e693237464207756e693237464307756e69323746 +4407756e693237464507756e693237464607756e693238303007756e693238303107756e693238303207756e693238303307 +756e693238303407756e693238303507756e693238303607756e693238303707756e693238303807756e693238303907756e +693238304107756e693238304207756e693238304307756e693238304407756e693238304507756e693238304607756e6932 +38313007756e693238313107756e693238313207756e693238313307756e693238313407756e693238313507756e69323831 +3607756e693238313707756e693238313807756e693238313907756e693238314107756e693238314207756e693238314307 +756e693238314407756e693238314507756e693238314607756e693238323007756e693238323107756e693238323207756e +693238323307756e693238323407756e693238323507756e693238323607756e693238323707756e693238323807756e6932 +38323907756e693238324107756e693238324207756e693238324307756e693238324407756e693238324507756e69323832 +4607756e693238333007756e693238333107756e693238333207756e693238333307756e693238333407756e693238333507 +756e693238333607756e693238333707756e693238333807756e693238333907756e693238334107756e693238334207756e +693238334307756e693238334407756e693238334507756e693238334607756e693238343007756e693238343107756e6932 +38343207756e693238343307756e693238343407756e693238343507756e693238343607756e693238343707756e69323834 +3807756e693238343907756e693238344107756e693238344207756e693238344307756e693238344407756e693238344507 +756e693238344607756e693238353007756e693238353107756e693238353207756e693238353307756e693238353407756e +693238353507756e693238353607756e693238353707756e693238353807756e693238353907756e693238354107756e6932 +38354207756e693238354307756e693238354407756e693238354507756e693238354607756e693238363007756e69323836 +3107756e693238363207756e693238363307756e693238363407756e693238363507756e693238363607756e693238363707 +756e693238363807756e693238363907756e693238364107756e693238364207756e693238364307756e693238364407756e +693238364507756e693238364607756e693238373007756e693238373107756e693238373207756e693238373307756e6932 +38373407756e693238373507756e693238373607756e693238373707756e693238373807756e693238373907756e69323837 +4107756e693238374207756e693238374307756e693238374407756e693238374507756e693238374607756e693238383007 +756e693238383107756e693238383207756e693238383307756e693238383407756e693238383507756e693238383607756e +693238383707756e693238383807756e693238383907756e693238384107756e693238384207756e693238384307756e6932 +38384407756e693238384507756e693238384607756e693238393007756e693238393107756e693238393207756e69323839 +3307756e693238393407756e693238393507756e693238393607756e693238393707756e693238393807756e693238393907 +756e693238394107756e693238394207756e693238394307756e693238394407756e693238394507756e693238394607756e +693238413007756e693238413107756e693238413207756e693238413307756e693238413407756e693238413507756e6932 +38413607756e693238413707756e693238413807756e693238413907756e693238414107756e693238414207756e69323841 +4307756e693238414407756e693238414507756e693238414607756e693238423007756e693238423107756e693238423207 +756e693238423307756e693238423407756e693238423507756e693238423607756e693238423707756e693238423807756e +693238423907756e693238424107756e693238424207756e693238424307756e693238424407756e693238424507756e6932 +38424607756e693238433007756e693238433107756e693238433207756e693238433307756e693238433407756e69323843 +3507756e693238433607756e693238433707756e693238433807756e693238433907756e693238434107756e693238434207 +756e693238434307756e693238434407756e693238434507756e693238434607756e693238443007756e693238443107756e +693238443207756e693238443307756e693238443407756e693238443507756e693238443607756e693238443707756e6932 +38443807756e693238443907756e693238444107756e693238444207756e693238444307756e693238444407756e69323844 +4507756e693238444607756e693238453007756e693238453107756e693238453207756e693238453307756e693238453407 +756e693238453507756e693238453607756e693238453707756e693238453807756e693238453907756e693238454107756e +693238454207756e693238454307756e693238454407756e693238454507756e693238454607756e693238463007756e6932 +38463107756e693238463207756e693238463307756e693238463407756e693238463507756e693238463607756e69323846 +3707756e693238463807756e693238463907756e693238464107756e693238464207756e693238464307756e693238464407 +756e693238464507756e693238464607756e693239303607756e693239303707756e693239304107756e693239304207756e +693239343007756e693239343107756e693239383307756e693239383407756e693239434507756e693239434607756e6932 +39443007756e693239443107756e693239443207756e693239443307756e693239443407756e693239443507756e69323945 +4207756e693239464107756e693239464207756e693241303007756e693241303107756e693241303207756e693241304307 +756e693241304407756e693241304507756e693241304607756e693241313007756e693241313107756e693241313207756e +693241313307756e693241313407756e693241313507756e693241313607756e693241313707756e693241313807756e6932 +41313907756e693241314107756e693241314207756e693241314307756e693241324607756e693241364107756e69324136 +4207756e693241374407756e693241374507756e693241374607756e693241383007756e693241383107756e693241383207 +756e693241383307756e693241383407756e693241383507756e693241383607756e693241383707756e693241383807756e +693241383907756e693241384107756e693241384207756e693241384307756e693241384407756e693241384507756e6932 +41384607756e693241393007756e693241393107756e693241393207756e693241393307756e693241393407756e69324139 +3507756e693241393607756e693241393707756e693241393807756e693241393907756e693241394107756e693241394207 +756e693241394307756e693241394407756e693241394507756e693241394607756e693241413007756e693241414507756e +693241414607756e693241423007756e693241423107756e693241423207756e693241423307756e693241423407756e6932 +41423507756e693241423607756e693241423707756e693241423807756e693241423907756e693241424107756e69324146 +3907756e693241464107756e693242303007756e693242303107756e693242303207756e693242303307756e693242303407 +756e693242303507756e693242303607756e693242303707756e693242303807756e693242303907756e693242304107756e +693242304207756e693242304307756e693242304407756e693242304507756e693242304607756e693242313007756e6932 +42313107756e693242313207756e693242313307756e693242313407756e693242313507756e693242313607756e69324231 +3707756e693242313807756e693242313907756e693242314107756e693242314607756e693242323007756e693242323107 +756e693242323207756e693242323307756e693242323407756e693242353307756e693242353407756e693243363007756e +693243363107756e693243363207756e693243363307756e693243363407756e693243363507756e693243363607756e6932 +43363707756e693243363807756e693243363907756e693243364107756e693243364207756e693243364307756e69324336 +4407756e693243364507756e693243364607756e693243373007756e693243373107756e693243373207756e693243373307 +756e693243373407756e693243373507756e693243373607756e693243373707756e693243373907756e693243374107756e +693243374207756e693243374307756e693243374407756e693243374507756e693243374607756e693244303007756e6932 +44303107756e693244303207756e693244303307756e693244303407756e693244303507756e693244303607756e69324430 +3707756e693244303807756e693244303907756e693244304107756e693244304207756e693244304307756e693244304407 +756e693244304507756e693244304607756e693244313007756e693244313107756e693244313207756e693244313307756e +693244313407756e693244313507756e693244313607756e693244313707756e693244313807756e693244313907756e6932 +44314107756e693244314207756e693244314307756e693244314407756e693244314507756e693244314607756e69324432 +3007756e693244323107756e693244323207756e693244323307756e693244323407756e693244323507756e693244333007 +756e693244333107756e693244333207756e693244333307756e693244333407756e693244333507756e693244333607756e +693244333707756e693244333807756e693244333907756e693244334107756e693244334207756e693244334307756e6932 +44334407756e693244334507756e693244334607756e693244343007756e693244343107756e693244343207756e69324434 +3307756e693244343407756e693244343507756e693244343607756e693244343707756e693244343807756e693244343907 +756e693244344107756e693244344207756e693244344307756e693244344407756e693244344507756e693244344607756e +693244353007756e693244353107756e693244353207756e693244353307756e693244353407756e693244353507756e6932 +44353607756e693244353707756e693244353807756e693244353907756e693244354107756e693244354207756e69324435 +4307756e693244354407756e693244354507756e693244354607756e693244363007756e693244363107756e693244363207 +756e693244363307756e693244363407756e693244363507756e693244364607756e693245313807756e693245314607756e +693245323207756e693245323307756e693245323407756e693245323507756e693245324507756e693444433007756e6934 +44433107756e693444433207756e693444433307756e693444433407756e693444433507756e693444433607756e69344443 +3707756e693444433807756e693444433907756e693444434107756e693444434207756e693444434307756e693444434407 +756e693444434507756e693444434607756e693444443007756e693444443107756e693444443207756e693444443307756e +693444443407756e693444443507756e693444443607756e693444443707756e693444443807756e693444443907756e6934 +44444107756e693444444207756e693444444307756e693444444407756e693444444507756e693444444607756e69344445 +3007756e693444453107756e693444453207756e693444453307756e693444453407756e693444453507756e693444453607 +756e693444453707756e693444453807756e693444453907756e693444454107756e693444454207756e693444454307756e +693444454407756e693444454507756e693444454607756e693444463007756e693444463107756e693444463207756e6934 +44463307756e693444463407756e693444463507756e693444463607756e693444463707756e693444463807756e69344446 +3907756e693444464107756e693444464207756e693444464307756e693444464407756e693444464507756e693444464607 +756e694134443007756e694134443107756e694134443207756e694134443307756e694134443407756e694134443507756e +694134443607756e694134443707756e694134443807756e694134443907756e694134444107756e694134444207756e6941 +34444307756e694134444407756e694134444507756e694134444607756e694134453007756e694134453107756e69413445 +3207756e694134453307756e694134453407756e694134453507756e694134453607756e694134453707756e694134453807 +756e694134453907756e694134454107756e694134454207756e694134454307756e694134454407756e694134454507756e +694134454607756e694134463007756e694134463107756e694134463207756e694134463307756e694134463407756e6941 +34463507756e694134463607756e694134463707756e694134463807756e694134463907756e694134464107756e69413446 +4207756e694134464307756e694134464407756e694134464507756e694134464607756e694136343407756e694136343507 +756e694136343607756e694136343707756e694136344307756e694136344407756e694136353007756e694136353107756e +694136353407756e694136353507756e694136353607756e694136353707756e694136363207756e694136363307756e6941 +36363407756e694136363507756e694136363607756e694136363707756e694136363807756e694136363907756e69413636 +4107756e694136364207756e694136364307756e694136364407756e694136364507756e694136384107756e694136384207 +756e694136384307756e694136384407756e694136393407756e694136393507756e694137303807756e694137303907756e +694137304107756e694137304207756e694137304307756e694137304407756e694137304507756e694137304607756e6941 +37313007756e694137313107756e694137313207756e694137313307756e694137313407756e694137313507756e69413731 +3607756e694137314207756e694137314307756e694137314407756e694137314507756e694137314607756e694137323207 +756e694137323307756e694137323407756e694137323507756e694137323607756e694137323707756e694137323807756e +694137323907756e694137324107756e694137324207756e694137333007756e694137333107756e694137333207756e6941 +37333307756e694137333407756e694137333507756e694137333607756e694137333707756e694137333807756e69413733 +3907756e694137334107756e694137334207756e694137334307756e694137334407756e694137334507756e694137334607 +756e694137343007756e694137343107756e694137343607756e694137343707756e694137343807756e694137343907756e +694137344107756e694137344207756e694137344507756e694137344607756e694137353007756e694137353107756e6941 +37353207756e694137353307756e694137353607756e694137353707756e694137363407756e694137363507756e69413736 +3607756e694137363707756e694137383007756e694137383107756e694137383207756e694137383307756e694137383907 +756e694137384107756e694137384207756e694137384307756e694137384407756e694137384507756e694137393007756e +694137393107756e694137413007756e694137413107756e694137413207756e694137413307756e694137413407756e6941 +37413507756e694137413607756e694137413707756e694137413807756e694137413907756e694137414107756e69413746 +3807756e694137463907756e694137464107756e694137464207756e694137464307756e694137464407756e694137464507 +756e694137464609756e69303245352e3509756e69303245362e3509756e69303245372e3509756e69303245382e3509756e +69303245392e3509756e69303245352e3409756e69303245362e3409756e69303245372e3409756e69303245382e3409756e +69303245392e3409756e69303245352e3309756e69303245362e3309756e69303245372e3309756e69303245382e3309756e +69303245392e3309756e69303245352e3209756e69303245362e3209756e69303245372e3209756e69303245382e3209756e +69303245392e3209756e69303245352e3109756e69303245362e3109756e69303245372e3109756e69303245382e3109756e +69303245392e31047374656d07756e694630303007756e694630303107756e694630303207756e694630303307756e694634 +303007756e694634303107756e694634303207756e694634303307756e694634303407756e694634303507756e6946343036 +07756e694634303707756e694634303807756e694634303907756e694634304107756e694634304207756e69463430430775 +6e694634304407756e694634304507756e694634304607756e694634313007756e694634313107756e694634313207756e69 +4634313307756e694634313407756e694634313507756e694634313607756e694634313707756e694634313807756e694634 +313907756e694634314107756e694634314207756e694634314307756e694634314407756e694634314507756e6946343146 +07756e694634323007756e694634323107756e694634323207756e694634323307756e694634323407756e69463432350775 +6e694634323607756e694634323807756e694634323907756e694634324107756e694634324207756e694634324307756e69 +4634324407756e694634324507756e694634324607756e694634333007756e694634333107756e694634333207756e694634 +333307756e694634333407756e694634333507756e694634333607756e694634333707756e694634333807756e6946343339 +07756e694634334107756e694634334207756e694634334307756e694634334407756e694634334507756e69463433460775 +6e694634343007756e694634343107756e694636433507756e694642303007756e694642303307756e694642303407756e69 +4642303507756e694642303607756e694642313307756e694642313407756e694642313507756e694642313607756e694642 +313707756e694642314407756e694642314507756e694642314607756e694642323007756e694642323107756e6946423232 +07756e694642323307756e694642323407756e694642323507756e694642323607756e694642323707756e69464232380775 +6e694642323907756e694642324107756e694642324207756e694642324307756e694642324407756e694642324507756e69 +4642324607756e694642333007756e694642333107756e694642333207756e694642333307756e694642333407756e694642 +333507756e694642333607756e694642333807756e694642333907756e694642334107756e694642334207756e6946423343 +07756e694642334507756e694642343007756e694642343107756e694642343307756e694642343407756e69464234360775 +6e694642343707756e694642343807756e694642343907756e694642344107756e694642344207756e694642344307756e69 +4642344407756e694642344507756e694642344607756e694642353207756e694642353307756e694642353407756e694642 +353507756e694642353607756e694642353707756e694642353807756e694642353907756e694642354107756e6946423542 +07756e694642354307756e694642354407756e694642354507756e694642354607756e694642363007756e69464236310775 +6e694642363207756e694642363307756e694642363407756e694642363507756e694642363607756e694642363707756e69 +4642363807756e694642363907756e694642364107756e694642364207756e694642364307756e694642364407756e694642 +364507756e694642364607756e694642373007756e694642373107756e694642373207756e694642373307756e6946423734 +07756e694642373507756e694642373607756e694642373707756e694642373807756e694642373907756e69464237410775 +6e694642374207756e694642374307756e694642374407756e694642374507756e694642374607756e694642383007756e69 +4642383107756e694642383207756e694642383307756e694642383407756e694642383507756e694642383607756e694642 +383707756e694642383807756e694642383907756e694642384107756e694642384207756e694642384307756e6946423844 +07756e694642384507756e694642384607756e694642393007756e694642393107756e694642393207756e69464239330775 +6e694642393407756e694642393507756e694642393607756e694642393707756e694642393807756e694642393907756e69 +4642394107756e694642394207756e694642394307756e694642394407756e694642394507756e694642394607756e694642 +413007756e694642413107756e694642413207756e694642413307756e694642414107756e694642414207756e6946424143 +07756e694642414407756e694642443307756e694642443407756e694642443507756e694642443607756e69464244370775 +6e694642443807756e694642443907756e694642444107756e694642444207756e694642444307756e694642444507756e69 +4642444607756e694642453407756e694642453507756e694642453607756e694642453707756e694642453807756e694642 +453907756e694642464307756e694642464407756e694642464507756e694642464607756e694645303007756e6946453031 +07756e694645303207756e694645303307756e694645303407756e694645303507756e694645303607756e69464530370775 +6e694645303807756e694645303907756e694645304107756e694645304207756e694645304307756e694645304407756e69 +4645304507756e694645304607756e694645323007756e694645323107756e694645323207756e694645323307756e694645 +373007756e694645373107756e694645373207756e694645373307756e694645373407756e694645373607756e6946453737 +07756e694645373807756e694645373907756e694645374107756e694645374207756e694645374307756e69464537440775 +6e694645374507756e694645374607756e694645383007756e694645383107756e694645383207756e694645383307756e69 +4645383407756e694645383507756e694645383607756e694645383707756e694645383807756e694645383907756e694645 +384107756e694645384207756e694645384307756e694645384407756e694645384507756e694645384607756e6946453930 +07756e694645393107756e694645393207756e694645393307756e694645393407756e694645393507756e69464539360775 +6e694645393707756e694645393807756e694645393907756e694645394107756e694645394207756e694645394307756e69 +4645394407756e694645394507756e694645394607756e694645413007756e694645413107756e694645413207756e694645 +413307756e694645413407756e694645413507756e694645413607756e694645413707756e694645413807756e6946454139 +07756e694645414107756e694645414207756e694645414307756e694645414407756e694645414507756e69464541460775 +6e694645423007756e694645423107756e694645423207756e694645423307756e694645423407756e694645423507756e69 +4645423607756e694645423707756e694645423807756e694645423907756e694645424107756e694645424207756e694645 +424307756e694645424407756e694645424507756e694645424607756e694645433007756e694645433107756e6946454332 +07756e694645433307756e694645433407756e694645433507756e694645433607756e694645433707756e69464543380775 +6e694645433907756e694645434107756e694645434207756e694645434307756e694645434407756e694645434507756e69 +4645434607756e694645443007756e694645443107756e694645443207756e694645443307756e694645443407756e694645 +443507756e694645443607756e694645443707756e694645443807756e694645443907756e694645444107756e6946454442 +07756e694645444307756e694645444407756e694645444507756e694645444607756e694645453007756e69464545310775 +6e694645453207756e694645453307756e694645453407756e694645453507756e694645453607756e694645453707756e69 +4645453807756e694645453907756e694645454107756e694645454207756e694645454307756e694645454407756e694645 +454507756e694645454607756e694645463007756e694645463107756e694645463207756e694645463307756e6946454634 +07756e694645463507756e694645463607756e694645463707756e694645463807756e694645463907756e69464546410775 +6e694645464207756e694645464307756e694645464607756e694646463907756e694646464107756e694646464207756e69 +4646464307756e69464646440675313033303006753130333031067531303330320675313033303306753130333034067531 +3033303506753130333036067531303330370675313033303806753130333039067531303330410675313033304206753130 +3330430675313033304406753130333045067531303330460675313033313006753130333131067531303331320675313033 +3133067531303331340675313033313506753130333136067531303331370675313033313806753130333139067531303331 +4106753130333142067531303331430675313033314406753130333145067531303332300675313033323106753130333232 +0675313033323306753144333030067531443330310675314433303206753144333033067531443330340675314433303506 +7531443330360675314433303706753144333038067531443330390675314433304106753144333042067531443330430675 +3144333044067531443330450675314433304606753144333130067531443331310675314433313206753144333133067531 +4433313406753144333135067531443331360675314433313706753144333138067531443331390675314433314106753144 +3331420675314433314306753144333144067531443331450675314433314606753144333230067531443332310675314433 +3232067531443332330675314433323406753144333235067531443332360675314433323706753144333238067531443332 +3906753144333241067531443332420675314433324306753144333244067531443332450675314433324606753144333330 +0675314433333106753144333332067531443333330675314433333406753144333335067531443333360675314433333706 +7531443333380675314433333906753144333341067531443333420675314433334306753144333344067531443333450675 +3144333346067531443334300675314433343106753144333432067531443334330675314433343406753144333435067531 +4433343606753144333437067531443334380675314433343906753144333441067531443334420675314433344306753144 +3334440675314433344506753144333446067531443335300675314433353106753144333532067531443335330675314433 +3534067531443335350675314433353606753144353338067531443533390675314435334206753144353343067531443533 +4406753144353345067531443534300675314435343106753144353432067531443534330675314435343406753144353436 +0675314435344106753144353442067531443534430675314435344406753144353445067531443534460675314435353006 +7531443535320675314435353306753144353534067531443535350675314435353606753144353537067531443535380675 +3144353539067531443535410675314435354206753144353543067531443535440675314435354506753144353546067531 +4435363006753144353631067531443536320675314435363306753144353634067531443536350675314435363606753144 +3536370675314435363806753144353639067531443536410675314435364206753144354130067531443541310675314435 +4132067531443541330675314435413406753144354135067531443541360675314435413706753144354138067531443541 +3906753144354141067531443541420675314435414306753144354144067531443541450675314435414606753144354230 +0675314435423106753144354232067531443542330675314435423406753144354235067531443542360675314435423706 +7531443542380675314435423906753144354241067531443542420675314435424306753144354244067531443542450675 +3144354246067531443543300675314435433106753144354332067531443543330675314435433406753144354335067531 +4435433606753144354337067531443543380675314435433906753144354341067531443543420675314435434306753144 +3543440675314435434506753144354346067531443544300675314435443106753144354432067531443544330675314437 +4438067531443744390675314437444106753144374442067531443744430675314437444406753144374445067531443744 +4606753144374530067531443745310675314437453206753144374533067531443745340675314437453506753144374536 +0675314437453706753144374538067531443745390675314437454106753144374542067531454530300675314545303106 +7531454530320675314545303306753145453035067531454530360675314545303706753145453038067531454530390675 +3145453041067531454530420675314545304306753145453044067531454530450675314545304606753145453130067531 +4545313106753145453132067531454531330675314545313406753145453135067531454531360675314545313706753145 +4531380675314545313906753145453141067531454531420675314545314306753145453144067531454531450675314545 +3146067531454532310675314545323206753145453234067531454532370675314545323906753145453241067531454532 +4206753145453243067531454532440675314545324506753145453246067531454533300675314545333106753145453332 +0675314545333406753145453335067531454533360675314545333706753145453339067531454533420675314545363106 +7531454536320675314545363406753145453637067531454536380675314545363906753145453641067531454536430675 +3145453644067531454536450675314545364606753145453730067531454537310675314545373206753145453734067531 +4545373506753145453736067531454537370675314545373906753145453741067531454537420675314545374306753145 +4537450675314630333006753146303331067531463033320675314630333306753146303334067531463033350675314630 +3336067531463033370675314630333806753146303339067531463033410675314630334206753146303343067531463033 +4406753146303345067531463033460675314630343006753146303431067531463034320675314630343306753146303434 +0675314630343506753146303436067531463034370675314630343806753146303439067531463034410675314630344206 +7531463034430675314630344406753146303445067531463034460675314630353006753146303531067531463035320675 +3146303533067531463035340675314630353506753146303536067531463035370675314630353806753146303539067531 +4630354106753146303542067531463035430675314630354406753146303545067531463035460675314630363006753146 +3036310675314630363206753146303633067531463036340675314630363506753146303636067531463036370675314630 +3638067531463036390675314630364106753146303642067531463036430675314630364406753146303645067531463036 +4606753146303730067531463037310675314630373206753146303733067531463037340675314630373506753146303736 +0675314630373706753146303738067531463037390675314630374106753146303742067531463037430675314630374406 +7531463037450675314630374606753146303830067531463038310675314630383206753146303833067531463038340675 +3146303835067531463038360675314630383706753146303838067531463038390675314630384106753146303842067531 +4630384306753146303844067531463038450675314630384606753146303930067531463039310675314630393206753146 +3039330675314630413006753146304131067531463041320675314630413306753146304134067531463041350675314630 +4136067531463041370675314630413806753146304139067531463041410675314630414206753146304143067531463041 +4406753146304145067531463042310675314630423206753146304233067531463042340675314630423506753146304236 +0675314630423706753146304238067531463042390675314630424106753146304242067531463042430675314630424406 +7531463042450675314630433106753146304332067531463043330675314630433406753146304335067531463043360675 +3146304337067531463043380675314630433906753146304341067531463043420675314630434306753146304344067531 +4630434506753146304346067531463044310675314630443206753146304433067531463044340675314630443506753146 +3044360675314630443706753146304438067531463044390675314630444106753146304442067531463044430675314630 +4444067531463044450675314630444606753146343244067531463432450675314634333106753146343335067531463630 +3006753146363031067531463630320675314636303306753146363034067531463630350675314636303606753146363037 +0675314636303806753146363039067531463630410675314636304206753146363043067531463630440675314636304506 +7531463630460000b8028040fffbfe03fa1403f92503f83203f79603f60e03f5fe03f4fe03f32503f20e03f19603f02503ef +8a4105effe03ee9603ed9603ecfa03ebfa03eafe03e93a03e84203e7fe03e63203e5e45305e59603e48a4105e45303e3e22f +05e3fa03e22f03e1fe03e0fe03df3203de1403dd9603dcfe03db1203da7d03d9bb03d8fe03d68a4105d67d03d5d44705d57d +03d44703d3d21b05d3fe03d21b03d1fe03d0fe03cffe03cefe03cd9603cccb1e05ccfe03cb1e03ca3203c9fe03c6851105c6 +1c03c51603c4fe03c3fe03c2fe03c1fe03c0fe03bffe03befe03bdfe03bcfe03bbfe03ba1103b9862505b9fe03b8b7bb05b8 +fe03b7b65d05b7bb03b78004b6b52505b65d40ff03b64004b52503b4fe03b39603b2fe03b1fe03b0fe03affe03ae6403ad0e +03acab2505ac6403abaa1205ab2503aa1203a98a4105a9fa03a8fe03a7fe03a6fe03a51203a4fe03a3a20e05a33203a20e03 +a16403a08a4105a096039ffe039e9d0c059efe039d0c039c9b19059c64039b9a10059b19039a1003990a0398fe0397960d05 +97fe03960d03958a410595960394930e05942803930e0392fa039190bb0591fe03908f5d0590bb039080048f8e25058f5d03 +8f40048e25038dfe038c8b2e058cfe038b2e038a8625058a410389880b05891403880b038786250587640386851105862503 +85110384fe038382110583fe0382110381fe0380fe037ffe0340ff7e7d7d057efe037d7d037c64037b5415057b25037afe03 +79fe03780e03770c03760a0375fe0374fa0373fa0372fa0371fa0370fe036ffe036efe036c21036bfe036a1142056a530369 +fe03687d036711420566fe0365fe0364fe0363fe0362fe03613a0360fa035e0c035dfe035bfe035afe0359580a0559fa0358 +0a035716190557320356fe035554150555420354150353011005531803521403514a130551fe03500b034ffe034e4d10054e +fe034d10034cfe034b4a13054bfe034a4910054a1303491d0d05491003480d0347fe0346960345960344fe0343022d0543fa +0342bb03414b0340fe033ffe033e3d12053e14033d3c0f053d12033c3b0d053c40ff0f033b0d033afe0339fe033837140538 +fa033736100537140336350b05361003350b03341e03330d0332310b0532fe03310b03302f0b05300d032f0b032e2d09052e +10032d09032c32032b2a25052b64032a2912052a25032912032827250528410327250326250b05260f03250b0324fe0323fe +03220f03210110052112032064031ffa031e1d0d051e64031d0d031c1142051cfe031bfa031a42031911420519fe03186403 +1716190517fe031601100516190315fe0314fe0313fe031211420512fe0311022d05114203107d030f64030efe030d0c1605 +0dfe030c0110050c16030bfe030a100309fe0308022d0508fe030714030664030401100504fe03401503022d0503fe030201 +1005022d0301100300fe0301b80164858d012b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b002b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b1d00>]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-0 16.000 selectfont +gsave + +195.836 362.531 translate +0 rotate +0 0 m /T glyphshow +11.5625 0 m /h glyphshow +20.4531 0 m /e glyphshow +27.5625 0 m /r glyphshow +33.8281 0 m /e glyphshow +40.9375 0 m /space glyphshow +46.2656 0 m /a glyphshow +54.2656 0 m /r glyphshow +60.5312 0 m /e glyphshow +67.6406 0 m /space glyphshow +72.9688 0 m /b glyphshow +81.8594 0 m /a glyphshow +89.8594 0 m /s glyphshow +96.1719 0 m /i glyphshow +100.609 0 m /c glyphshow +107.719 0 m /space glyphshow +113.047 0 m /c glyphshow +120.156 0 m /h glyphshow +129.047 0 m /a glyphshow +137.047 0 m /r glyphshow +143.312 0 m /a glyphshow +151.312 0 m /c glyphshow +158.422 0 m /t glyphshow +164.641 0 m /e glyphshow +171.75 0 m /r glyphshow +178.016 0 m /s glyphshow +grestore +/Cmr10-0 16.000 selectfont +gsave + +34.5859 347.781 translate +0 rotate +0 0 m /A glyphshow +12 0 m /B glyphshow +23.3281 0 m /C glyphshow +34.8906 0 m /D glyphshow +47.1094 0 m /E glyphshow +58 0 m /F glyphshow +68.4375 0 m /G glyphshow +80.9844 0 m /H glyphshow +92.9844 0 m /I glyphshow +98.7656 0 m /J glyphshow +106.984 0 m /K glyphshow +119.422 0 m /L glyphshow +129.422 0 m /M glyphshow +144.078 0 m /N glyphshow +156.078 0 m /O glyphshow +168.516 0 m /P glyphshow +179.406 0 m /Q glyphshow +191.844 0 m /R glyphshow +203.625 0 m /S glyphshow +212.516 0 m /T glyphshow +224.078 0 m /U glyphshow +236.078 0 m /V glyphshow +248.078 0 m /W glyphshow +264.516 0 m /X glyphshow +276.516 0 m /Y glyphshow +288.516 0 m /Z glyphshow +298.297 0 m /space glyphshow +303.625 0 m /a glyphshow +311.625 0 m /b glyphshow +320.516 0 m /c glyphshow +327.625 0 m /d glyphshow +336.516 0 m /e glyphshow +343.625 0 m /f glyphshow +348.516 0 m /g glyphshow +356.516 0 m /h glyphshow +365.406 0 m /i glyphshow +369.844 0 m /j glyphshow +374.734 0 m /k glyphshow +383.172 0 m /l glyphshow +387.609 0 m /m glyphshow +400.938 0 m /n glyphshow +409.828 0 m /o glyphshow +417.828 0 m /p glyphshow +426.719 0 m /q glyphshow +435.156 0 m /r glyphshow +441.422 0 m /s glyphshow +447.734 0 m /t glyphshow +453.953 0 m /u glyphshow +462.844 0 m /v glyphshow +471.281 0 m /w glyphshow +482.844 0 m /x glyphshow +491.281 0 m /y glyphshow +499.719 0 m /z glyphshow +grestore +/Cmr10-0 16.000 selectfont +gsave + +122.281 332.484 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.7656 0 m /quotedblright glyphshow +97.7656 0 m /numbersign glyphshow +111.094 0 m /dollar glyphshow +119.094 0 m /percent glyphshow +132.422 0 m /ampersand glyphshow +144.859 0 m /quoteright glyphshow +149.297 0 m /parenleft glyphshow +155.516 0 m /parenright glyphshow +161.734 0 m /asterisk glyphshow +169.734 0 m /plus glyphshow +182.172 0 m /comma glyphshow +186.609 0 m /hyphen glyphshow +191.938 0 m /period glyphshow +196.375 0 m /slash glyphshow +204.375 0 m /colon glyphshow +208.812 0 m /semicolon glyphshow +213.25 0 m /exclamdown glyphshow +217.688 0 m /equal glyphshow +230.125 0 m /questiondown glyphshow +237.688 0 m /question glyphshow +245.25 0 m /at glyphshow +257.688 0 m /bracketleft glyphshow +262.125 0 m /quotedblleft glyphshow +270.125 0 m /bracketright glyphshow +274.562 0 m /circumflex glyphshow +282.562 0 m /dotaccent glyphshow +287 0 m /quoteleft glyphshow +291.438 0 m /emdash glyphshow +299.438 0 m /endash glyphshow +315.438 0 m /hungarumlaut glyphshow +323.438 0 m /tilde glyphshow +grestore +/Cmr10-0 16.000 selectfont +gsave + +203.922 317.203 translate +0 rotate +0 0 m /a glyphshow +8 0 m /n glyphshow +16.8906 0 m /d glyphshow +25.7812 0 m /space glyphshow +31.1094 0 m /a glyphshow +39.1094 0 m /c glyphshow +46.2188 0 m /c glyphshow +53.3281 0 m /e glyphshow +60.4375 0 m /n glyphshow +69.3281 0 m /t glyphshow +75.5469 0 m /e glyphshow +82.6562 0 m /d glyphshow +91.5469 0 m /space glyphshow +96.875 0 m /c glyphshow +103.984 0 m /h glyphshow +112.875 0 m /a glyphshow +120.875 0 m /r glyphshow +127.141 0 m /a glyphshow +135.141 0 m /c glyphshow +142.25 0 m /t glyphshow +148.469 0 m /e glyphshow +155.578 0 m /r glyphshow +161.844 0 m /s glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +144.602 299.047 translate +0 rotate +0 0 m /Aring glyphshow +10.9531 0 m /AE glyphshow +26.5469 0 m /Ccedilla glyphshow +37.7188 0 m /Egrave glyphshow +47.8281 0 m /Eacute glyphshow +57.9375 0 m /Ecircumflex glyphshow +68.0469 0 m /Edieresis glyphshow +78.1562 0 m /Igrave glyphshow +82.875 0 m /Iacute glyphshow +87.5938 0 m /Icircumflex glyphshow +92.3125 0 m /Idieresis glyphshow +97.0312 0 m /Eth glyphshow +109.438 0 m /Ntilde glyphshow +121.406 0 m /Ograve glyphshow +134 0 m /Oacute glyphshow +146.594 0 m /Ocircumflex glyphshow +159.188 0 m /Otilde glyphshow +171.781 0 m /Odieresis glyphshow +184.375 0 m /multiply glyphshow +197.781 0 m /Oslash glyphshow +210.375 0 m /Ugrave glyphshow +222.094 0 m /Uacute glyphshow +233.812 0 m /Ucircumflex glyphshow +245.531 0 m /Udieresis glyphshow +257.25 0 m /Yacute glyphshow +267.031 0 m /Thorn glyphshow +276.719 0 m /germandbls glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +136.82 281.703 translate +0 rotate +0 0 m /agrave glyphshow +9.8125 0 m /aacute glyphshow +19.625 0 m /acircumflex glyphshow +29.4375 0 m /atilde glyphshow +39.25 0 m /adieresis glyphshow +49.0625 0 m /aring glyphshow +58.875 0 m /ae glyphshow +74.5938 0 m /ccedilla glyphshow +83.3906 0 m /egrave glyphshow +93.2344 0 m /eacute glyphshow +103.078 0 m /ecircumflex glyphshow +112.922 0 m /edieresis glyphshow +122.766 0 m /igrave glyphshow +127.219 0 m /iacute glyphshow +131.672 0 m /icircumflex glyphshow +136.125 0 m /idieresis glyphshow +140.578 0 m /eth glyphshow +150.375 0 m /ntilde glyphshow +160.516 0 m /ograve glyphshow +170.312 0 m /oacute glyphshow +180.109 0 m /ocircumflex glyphshow +189.906 0 m /otilde glyphshow +199.703 0 m /odieresis glyphshow +209.5 0 m /divide glyphshow +222.906 0 m /oslash glyphshow +232.703 0 m /ugrave glyphshow +242.844 0 m /uacute glyphshow +252.984 0 m /ucircumflex glyphshow +263.125 0 m /udieresis glyphshow +273.266 0 m /yacute glyphshow +282.734 0 m /thorn glyphshow +292.891 0 m /ydieresis glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +121.945 263.234 translate +0 rotate +0 0 m /Amacron glyphshow +10.9531 0 m /amacron glyphshow +20.7656 0 m /Abreve glyphshow +31.7188 0 m /abreve glyphshow +41.5312 0 m /Aogonek glyphshow +52.4844 0 m /aogonek glyphshow +62.2969 0 m /Cacute glyphshow +73.4688 0 m /cacute glyphshow +82.2656 0 m /Ccircumflex glyphshow +93.4375 0 m /ccircumflex glyphshow +102.234 0 m /Cdotaccent glyphshow +113.406 0 m /cdotaccent glyphshow +122.203 0 m /Ccaron glyphshow +133.375 0 m /ccaron glyphshow +142.172 0 m /Dcaron glyphshow +154.5 0 m /dcaron glyphshow +164.656 0 m /Dcroat glyphshow +177.062 0 m /dcroat glyphshow +187.219 0 m /Emacron glyphshow +197.328 0 m /emacron glyphshow +207.172 0 m /Ebreve glyphshow +217.281 0 m /ebreve glyphshow +227.125 0 m /Edotaccent glyphshow +237.234 0 m /edotaccent glyphshow +247.078 0 m /Eogonek glyphshow +257.188 0 m /eogonek glyphshow +267.031 0 m /Ecaron glyphshow +277.141 0 m /ecaron glyphshow +286.984 0 m /Gcircumflex glyphshow +299.391 0 m /gcircumflex glyphshow +309.547 0 m /Gbreve glyphshow +321.953 0 m /gbreve glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +164.969 245.047 translate +0 rotate +0 0 m /Gdotaccent glyphshow +12.4062 0 m /gdotaccent glyphshow +22.5625 0 m /Gcommaaccent glyphshow +34.9688 0 m /gcommaaccent glyphshow +45.125 0 m /Hcircumflex glyphshow +57.1562 0 m /hcircumflex glyphshow +67.2969 0 m /Hbar glyphshow +81.9531 0 m /hbar glyphshow +93.0781 0 m /Itilde glyphshow +97.7969 0 m /itilde glyphshow +102.25 0 m /Imacron glyphshow +106.969 0 m /imacron glyphshow +111.422 0 m /Ibreve glyphshow +116.141 0 m /ibreve glyphshow +120.594 0 m /Iogonek glyphshow +125.312 0 m /iogonek glyphshow +129.766 0 m /Idotaccent glyphshow +134.484 0 m /dotlessi glyphshow +138.938 0 m /IJ glyphshow +148.375 0 m /ij glyphshow +157.266 0 m /Jcircumflex glyphshow +161.984 0 m /jcircumflex glyphshow +166.438 0 m /Kcommaaccent glyphshow +176.938 0 m /kcommaaccent glyphshow +186.203 0 m /kgreenlandic glyphshow +195.469 0 m /Lacute glyphshow +204.391 0 m /lacute glyphshow +208.844 0 m /Lcommaaccent glyphshow +217.766 0 m /lcommaaccent glyphshow +222.219 0 m /Lcaron glyphshow +231.141 0 m /lcaron glyphshow +237.141 0 m /Ldot glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +123.125 226.188 translate +0 rotate +0 0 m /ldot glyphshow +5.46875 0 m /Lslash glyphshow +14.4688 0 m /lslash glyphshow +19.0156 0 m /Nacute glyphshow +30.9844 0 m /nacute glyphshow +41.125 0 m /Ncommaaccent glyphshow +53.0938 0 m /ncommaaccent glyphshow +63.2344 0 m /Ncaron glyphshow +75.2031 0 m /ncaron glyphshow +85.3438 0 m /napostrophe glyphshow +98.3594 0 m /Eng glyphshow +110.328 0 m /eng glyphshow +120.469 0 m /Omacron glyphshow +133.062 0 m /omacron glyphshow +142.859 0 m /Obreve glyphshow +155.453 0 m /obreve glyphshow +165.25 0 m /Ohungarumlaut glyphshow +177.844 0 m /ohungarumlaut glyphshow +187.641 0 m /OE glyphshow +204.766 0 m /oe glyphshow +221.141 0 m /Racute glyphshow +232.266 0 m /racute glyphshow +238.844 0 m /Rcommaaccent glyphshow +249.969 0 m /rcommaaccent glyphshow +256.547 0 m /Rcaron glyphshow +267.672 0 m /rcaron glyphshow +274.25 0 m /Sacute glyphshow +284.406 0 m /sacute glyphshow +292.75 0 m /Scircumflex glyphshow +302.906 0 m /scircumflex glyphshow +311.25 0 m /Scedilla glyphshow +321.406 0 m /scedilla glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +128.219 207.516 translate +0 rotate +0 0 m /Scaron glyphshow +10.1562 0 m /scaron glyphshow +18.5 0 m /Tcommaaccent glyphshow +28.2812 0 m /tcommaaccent glyphshow +34.5625 0 m /Tcaron glyphshow +44.3438 0 m /tcaron glyphshow +50.625 0 m /Tbar glyphshow +60.4062 0 m /tbar glyphshow +66.6875 0 m /Utilde glyphshow +78.4062 0 m /utilde glyphshow +88.5469 0 m /Umacron glyphshow +100.266 0 m /umacron glyphshow +110.406 0 m /Ubreve glyphshow +122.125 0 m /ubreve glyphshow +132.266 0 m /Uring glyphshow +143.984 0 m /uring glyphshow +154.125 0 m /Uhungarumlaut glyphshow +165.844 0 m /uhungarumlaut glyphshow +175.984 0 m /Uogonek glyphshow +187.703 0 m /uogonek glyphshow +197.844 0 m /Wcircumflex glyphshow +213.672 0 m /wcircumflex glyphshow +226.766 0 m /Ycircumflex glyphshow +236.547 0 m /ycircumflex glyphshow +246.016 0 m /Ydieresis glyphshow +255.797 0 m /Zacute glyphshow +266.766 0 m /zacute glyphshow +275.172 0 m /Zdotaccent glyphshow +286.141 0 m /zdotaccent glyphshow +294.547 0 m /Zcaron glyphshow +305.516 0 m /zcaron glyphshow +313.922 0 m /longs glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +120.906 189.406 translate +0 rotate +0 0 m /uni0180 glyphshow +10.1562 0 m /uni0181 glyphshow +21.9219 0 m /uni0182 glyphshow +32.9062 0 m /uni0183 glyphshow +43.0625 0 m /uni0184 glyphshow +54.0469 0 m /uni0185 glyphshow +64.2031 0 m /uni0186 glyphshow +75.4531 0 m /uni0187 glyphshow +86.625 0 m /uni0188 glyphshow +95.4219 0 m /uni0189 glyphshow +107.828 0 m /uni018A glyphshow +120.938 0 m /uni018B glyphshow +131.922 0 m /uni018C glyphshow +142.078 0 m /uni018D glyphshow +151.875 0 m /uni018E glyphshow +161.984 0 m /uni018F glyphshow +174.578 0 m /uni0190 glyphshow +184.406 0 m /uni0191 glyphshow +193.609 0 m /florin glyphshow +199.25 0 m /uni0193 glyphshow +211.656 0 m /uni0194 glyphshow +222.641 0 m /uni0195 glyphshow +238.391 0 m /uni0196 glyphshow +244.047 0 m /uni0197 glyphshow +248.766 0 m /uni0198 glyphshow +260.703 0 m /uni0199 glyphshow +269.969 0 m /uni019A glyphshow +274.422 0 m /uni019B glyphshow +283.891 0 m /uni019C glyphshow +299.484 0 m /uni019D glyphshow +311.453 0 m /uni019E glyphshow +321.594 0 m /uni019F glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +124.211 173.891 translate +0 rotate +0 0 m /Ohorn glyphshow +14.6094 0 m /ohorn glyphshow +24.4062 0 m /uni01A2 glyphshow +39.5938 0 m /uni01A3 glyphshow +51.75 0 m /uni01A4 glyphshow +62.1875 0 m /uni01A5 glyphshow +72.3438 0 m /uni01A6 glyphshow +83.4688 0 m /uni01A7 glyphshow +93.625 0 m /uni01A8 glyphshow +101.969 0 m /uni01A9 glyphshow +112.078 0 m /uni01AA glyphshow +117.453 0 m /uni01AB glyphshow +123.734 0 m /uni01AC glyphshow +133.516 0 m /uni01AD glyphshow +139.797 0 m /uni01AE glyphshow +149.578 0 m /Uhorn glyphshow +163.312 0 m /uhorn glyphshow +173.453 0 m /uni01B1 glyphshow +185.688 0 m /uni01B2 glyphshow +197.219 0 m /uni01B3 glyphshow +209.125 0 m /uni01B4 glyphshow +220.812 0 m /uni01B5 glyphshow +231.781 0 m /uni01B6 glyphshow +240.188 0 m /uni01B7 glyphshow +250.844 0 m /uni01B8 glyphshow +261.5 0 m /uni01B9 glyphshow +270.75 0 m /uni01BA glyphshow +279.156 0 m /uni01BB glyphshow +289.344 0 m /uni01BC glyphshow +300 0 m /uni01BD glyphshow +309.25 0 m /uni01BE glyphshow +317.422 0 m /uni01BF glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +110.68 153.734 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.6719 0 m /uni01C4 glyphshow +47.4219 0 m /uni01C5 glyphshow +68.2031 0 m /uni01C6 glyphshow +86.6719 0 m /uni01C7 glyphshow +100.047 0 m /uni01C8 glyphshow +112.641 0 m /uni01C9 glyphshow +119.953 0 m /uni01CA glyphshow +134.859 0 m /uni01CB glyphshow +149.641 0 m /uni01CC glyphshow +162.406 0 m /uni01CD glyphshow +173.359 0 m /uni01CE glyphshow +183.172 0 m /uni01CF glyphshow +187.891 0 m /uni01D0 glyphshow +192.344 0 m /uni01D1 glyphshow +204.938 0 m /uni01D2 glyphshow +214.734 0 m /uni01D3 glyphshow +226.453 0 m /uni01D4 glyphshow +236.594 0 m /uni01D5 glyphshow +248.312 0 m /uni01D6 glyphshow +258.453 0 m /uni01D7 glyphshow +270.172 0 m /uni01D8 glyphshow +280.312 0 m /uni01D9 glyphshow +292.031 0 m /uni01DA glyphshow +302.172 0 m /uni01DB glyphshow +313.891 0 m /uni01DC glyphshow +324.031 0 m /uni01DD glyphshow +333.875 0 m /uni01DE glyphshow +344.828 0 m /uni01DF glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +90.0078 134 translate +0 rotate +0 0 m /uni01E0 glyphshow +10.9531 0 m /uni01E1 glyphshow +20.7656 0 m /uni01E2 glyphshow +36.3594 0 m /uni01E3 glyphshow +52.0781 0 m /uni01E4 glyphshow +64.4844 0 m /uni01E5 glyphshow +74.6406 0 m /Gcaron glyphshow +87.0469 0 m /gcaron glyphshow +97.2031 0 m /uni01E8 glyphshow +107.703 0 m /uni01E9 glyphshow +116.969 0 m /uni01EA glyphshow +129.562 0 m /uni01EB glyphshow +139.359 0 m /uni01EC glyphshow +151.953 0 m /uni01ED glyphshow +161.75 0 m /uni01EE glyphshow +172.406 0 m /uni01EF glyphshow +181.656 0 m /uni01F0 glyphshow +186.109 0 m /uni01F1 glyphshow +208.859 0 m /uni01F2 glyphshow +229.641 0 m /uni01F3 glyphshow +248.109 0 m /uni01F4 glyphshow +260.516 0 m /uni01F5 glyphshow +270.672 0 m /uni01F6 glyphshow +288.484 0 m /uni01F7 glyphshow +299.406 0 m /uni01F8 glyphshow +311.375 0 m /uni01F9 glyphshow +321.516 0 m /Aringacute glyphshow +332.469 0 m /aringacute glyphshow +342.281 0 m /AEacute glyphshow +357.875 0 m /aeacute glyphshow +373.594 0 m /Oslashacute glyphshow +386.188 0 m /oslashacute glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +138.602 115.719 translate +0 rotate +0 0 m /uni0200 glyphshow +10.9531 0 m /uni0201 glyphshow +20.7656 0 m /uni0202 glyphshow +31.7188 0 m /uni0203 glyphshow +41.5312 0 m /uni0204 glyphshow +51.6406 0 m /uni0205 glyphshow +61.4844 0 m /uni0206 glyphshow +71.5938 0 m /uni0207 glyphshow +81.4375 0 m /uni0208 glyphshow +86.1562 0 m /uni0209 glyphshow +90.6094 0 m /uni020A glyphshow +95.3281 0 m /uni020B glyphshow +99.7812 0 m /uni020C glyphshow +112.375 0 m /uni020D glyphshow +122.172 0 m /uni020E glyphshow +134.766 0 m /uni020F glyphshow +144.562 0 m /uni0210 glyphshow +155.688 0 m /uni0211 glyphshow +162.266 0 m /uni0212 glyphshow +173.391 0 m /uni0213 glyphshow +179.969 0 m /uni0214 glyphshow +191.688 0 m /uni0215 glyphshow +201.828 0 m /uni0216 glyphshow +213.547 0 m /uni0217 glyphshow +223.688 0 m /Scommaaccent glyphshow +233.844 0 m /scommaaccent glyphshow +242.188 0 m /uni021A glyphshow +251.969 0 m /uni021B glyphshow +258.25 0 m /uni021C glyphshow +268.281 0 m /uni021D glyphshow +276.625 0 m /uni021E glyphshow +288.656 0 m /uni021F glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +118.953 95.4688 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.0781 0 m /uni0225 glyphshow +65.4844 0 m /uni0226 glyphshow +76.4375 0 m /uni0227 glyphshow +86.25 0 m /uni0228 glyphshow +96.3594 0 m /uni0229 glyphshow +106.203 0 m /uni022A glyphshow +118.797 0 m /uni022B glyphshow +128.594 0 m /uni022C glyphshow +141.188 0 m /uni022D glyphshow +150.984 0 m /uni022E glyphshow +163.578 0 m /uni022F glyphshow +173.375 0 m /uni0230 glyphshow +185.969 0 m /uni0231 glyphshow +195.766 0 m /uni0232 glyphshow +205.547 0 m /uni0233 glyphshow +215.016 0 m /uni0234 glyphshow +222.609 0 m /uni0235 glyphshow +236.094 0 m /uni0236 glyphshow +243.734 0 m /dotlessj glyphshow +248.188 0 m /uni0238 glyphshow +264.156 0 m /uni0239 glyphshow +280.125 0 m /uni023A glyphshow +291.078 0 m /uni023B glyphshow +302.25 0 m /uni023C glyphshow +311.047 0 m /uni023D glyphshow +319.969 0 m /uni023E glyphshow +329.75 0 m /uni023F glyphshow +grestore +/DejaVuSans-0 16.000 selectfont +gsave + +79.4297 76.8125 translate +0 rotate +0 0 m /uni0240 glyphshow +8.40625 0 m /uni0241 glyphshow +18.0625 0 m /uni0242 glyphshow +25.7344 0 m /uni0243 glyphshow +36.7188 0 m /uni0244 glyphshow +48.4375 0 m /uni0245 glyphshow +59.3906 0 m /uni0246 glyphshow +69.5 0 m /uni0247 glyphshow +79.3438 0 m /uni0248 glyphshow +84.0625 0 m /uni0249 glyphshow +88.5156 0 m /uni024A glyphshow +101.016 0 m /uni024B glyphshow +111.172 0 m /uni024C glyphshow +122.297 0 m /uni024D glyphshow +128.875 0 m /uni024E glyphshow +138.656 0 m /uni024F glyphshow +grestore +/DejaVuSans-1 16.000 selectfont +gsave + +79.4297 76.8125 translate +0 rotate +148.125 0 m /u1F600 glyphshow +164.812 0 m /u1F601 glyphshow +181.5 0 m /u1F602 glyphshow +200.203 0 m /u1F603 glyphshow +216.891 0 m /u1F604 glyphshow +233.578 0 m /u1F605 glyphshow +250.266 0 m /u1F606 glyphshow +266.953 0 m /u1F607 glyphshow +283.641 0 m /u1F608 glyphshow +300.328 0 m /u1F609 glyphshow +317.016 0 m /u1F60A glyphshow +333.703 0 m /u1F60B glyphshow +350.391 0 m /u1F60C glyphshow +367.078 0 m /u1F60D glyphshow +383.766 0 m /u1F60E glyphshow +400.453 0 m /u1F60F glyphshow +grestore +/Cmr10-0 16.000 selectfont +gsave + +248.008 61.4844 translate +0 rotate +0 0 m /i glyphshow +4.4375 0 m /n glyphshow +13.3281 0 m /space glyphshow +18.6562 0 m /b glyphshow +27.5469 0 m /e glyphshow +34.6562 0 m /t glyphshow +40.875 0 m /w glyphshow +52.4375 0 m /e glyphshow +59.5469 0 m /e glyphshow +66.6562 0 m /n glyphshow +75.5469 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/ttc_type3.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type3.eps new file mode 100644 index 000000000000..cc4bff1ec687 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type3.eps @@ -0,0 +1,1483 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: ttc_type3.eps +%%Creator: Matplotlib v3.11.0.dev2075+g5a13dc378e, https://matplotlib.org/ +%%CreationDate: Fri Mar 13 23:13:37 2026 +%%Orientation: portrait +%%BoundingBox: 0 0 504 72 +%%HiResBoundingBox: 0.000000 0.000000 504.000000 72.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 /WenQuanYiZenHei-0 def +/PaintType 0 def +/FontMatrix [0.0009765625 0 0 0.0009765625 0 0] def +/FontBBox [-129 -304 1076 986] def +/FontType 3 def +/Encoding [/W /e /n /Q /u /a /Y /i /space /Z /H /colon /A /B /C /D /E /F /G /I /J /K /L /M /N /O /P /R /S /T /U /V /X] def +/CharStrings 34 dict dup begin +/.notdef 0 def +/W{839 0 11 0 831 702 sc +831 702 m +663 0 l +574 0 l +422 545 l +279 0 l +189 0 l +11 702 l +101 702 l +242 133 l +244 133 l +392 702 l +463 702 l +623 133 l +625 133 l +755 702 l +831 702 l + +ce} _d +/e{552 0 38 -10 506 534 sc +506 254 m +128 254 l +127 187 143 136 174 101 c +200 72 236 57 283 57 c +341 57 384 82 411 133 c +415 140 419 149 422 158 c +498 142 l +479 82 439 38 378 11 c +346 -3 312 -10 276 -10 c +187 -10 121 27 78 100 c +51 145 38 199 38 260 c +38 346 64 415 116 468 c +159 512 213 534 279 534 c +369 534 434 495 473 417 c +495 374 506 323 506 266 c +506 254 l + +418 313 m +419 370 401 413 366 442 c +342 462 313 472 279 472 c +226 472 186 448 158 400 c +142 374 133 345 132 313 c +418 313 l + +ce} _d +/n{552 0 71 0 482 534 sc +482 0 m +402 0 l +402 322 l +402 366 398 396 391 412 c +390 414 389 416 388 418 c +373 444 348 459 313 464 c +308 465 304 465 299 465 c +234 465 190 432 166 366 c +156 337 151 306 151 272 c +151 0 l +71 0 l +71 520 l +146 520 l +146 424 l +148 424 l +173 477 211 511 263 526 c +278 531 294 534 310 534 c +375 534 423 508 455 457 c +458 453 l +474 425 482 377 482 309 c +482 0 l + +ce} _d +/Q{675 0 42 -167 626 713 sc +626 351 m +626 244 599 158 546 91 c +509 46 462 16 407 1 c +407 -14 l +407 -55 425 -80 461 -88 c +468 -90 476 -91 485 -91 c +500 -91 532 -89 580 -84 c +580 -154 l +553 -163 528 -167 504 -167 c +412 -167 357 -130 340 -55 c +337 -41 335 -26 335 -10 c +224 -7 142 41 91 135 c +58 195 42 265 42 346 c +42 456 69 545 124 613 c +177 680 247 713 334 713 c +441 713 520 666 572 572 c +608 509 626 436 626 351 c + +530 349 m +530 482 496 569 428 610 c +401 627 370 635 333 635 c +234 635 172 576 147 459 c +140 424 136 386 136 344 c +136 239 160 161 207 112 c +238 79 278 62 327 62 c +425 62 488 116 516 225 c +525 263 530 304 530 349 c + +ce} _d +/u{552 0 71 -10 479 520 sc +479 0 m +407 0 l +407 103 l +404 103 l +386 58 355 25 310 4 c +289 -5 268 -10 245 -10 c +144 -10 87 45 74 156 c +72 171 71 187 71 204 c +71 520 l +151 520 l +151 204 l +151 113 181 65 242 59 c +242 59 245 59 252 59 c +311 59 354 89 380 148 c +393 177 399 209 399 244 c +399 520 l +479 520 l +479 0 l + +ce} _d +/a{552 0 56 -10 509 534 sc +509 0 m +429 0 l +420 97 l +385 26 324 -10 238 -10 c +171 -10 120 11 87 53 c +66 79 56 110 56 147 c +56 198 78 240 122 273 c +131 281 142 287 153 292 c +198 313 272 324 375 323 c +420 323 l +420 345 l +420 409 397 448 352 463 c +316 470 l +307 471 298 471 288 471 c +205 471 158 440 145 379 c +71 391 l +80 458 124 502 205 522 c +233 530 263 534 295 534 c +384 534 442 510 469 463 c +488 431 498 380 498 311 c +498 110 l +498 63 502 26 509 0 c + +420 228 m +420 262 l +353 262 l +212 262 142 222 142 143 c +142 100 165 71 211 58 c +224 54 239 52 255 52 c +312 52 356 76 388 123 c +409 154 420 189 420 228 c + +ce} _d +/Y{573 0 11 0 568 702 sc +568 702 m +334 296 l +334 0 l +246 0 l +246 296 l +11 702 l +114 702 l +300 379 l +488 702 l +568 702 l + +ce} _d +/i{245 0 79 0 167 702 sc +167 612 m +79 612 l +79 702 l +167 702 l +167 612 l + +163 0 m +83 0 l +83 520 l +163 520 l +163 0 l + +ce} _d +/space{307 0 0 0 0 0 sc +ce} _d +/Z{552 0 17 0 513 702 sc +513 0 m +17 0 l +17 76 l +399 630 l +35 630 l +35 702 l +502 702 l +502 644 l +116 76 l +513 76 l +513 0 l + +ce} _d +/H{675 0 83 0 585 702 sc +585 0 m +497 0 l +497 334 l +171 334 l +171 0 l +83 0 l +83 702 l +171 702 l +171 411 l +497 411 l +497 702 l +585 702 l +585 0 l + +ce} _d +/colon{307 0 101 0 215 520 sc +215 404 m +101 404 l +101 520 l +215 520 l +215 404 l + +215 0 m +101 0 l +101 116 l +215 116 l +215 0 l + +ce} _d +/A{573 0 11 0 568 702 sc +568 0 m +478 0 l +408 205 l +147 205 l +85 0 l +11 0 l +239 702 l +340 702 l +568 0 l + +388 271 m +281 608 l +172 271 l +388 271 l + +ce} _d +/B{634 0 83 0 588 702 sc +588 194 m +588 130 565 80 520 45 c +484 16 434 1 370 0 c +347 0 l +83 0 l +83 702 l +348 702 l +405 702 448 694 477 679 c +482 676 487 673 493 670 c +541 637 565 591 566 531 c +566 470 542 424 494 394 c +462 380 l +456 377 449 375 442 374 c +442 372 l +501 359 543 327 568 276 c +581 251 588 224 588 194 c + +479 520 m +479 585 443 621 370 630 c +361 631 351 631 341 631 c +171 631 l +171 401 l +317 401 l +425 401 479 441 479 520 c + +500 198 m +500 241 485 276 454 303 c +453 304 451 306 449 307 c +426 325 389 334 338 334 c +171 334 l +171 75 l +343 75 l +432 75 483 105 497 166 c +499 175 500 186 500 198 c + +ce} _d +/C{634 0 43 -10 589 713 sc +589 219 m +558 90 490 16 386 -5 c +367 -8 348 -10 329 -10 c +224 -10 146 38 94 135 c +60 199 43 273 43 358 c +43 471 72 560 131 626 c +183 684 251 713 336 713 c +435 713 508 669 555 582 c +570 554 582 523 589 488 c +506 473 l +479 573 430 628 359 637 c +350 638 342 639 333 639 c +248 639 190 590 159 492 c +146 449 139 402 139 351 c +139 261 158 189 197 134 c +230 87 274 63 329 63 c +418 63 477 117 506 225 c +507 229 508 233 509 237 c +589 219 l + +ce} _d +/D{675 0 87 0 636 702 sc +636 353 m +636 247 607 160 550 93 c +496 31 425 0 338 0 c +87 0 l +87 702 l +309 702 l +394 702 462 682 512 642 c +525 631 538 618 551 603 c +608 537 636 454 636 353 c + +547 353 m +547 436 525 504 482 557 c +449 599 403 623 344 628 c +304 629 l +175 629 l +175 75 l +304 75 l +382 75 440 97 478 140 c +484 147 490 155 496 164 c +530 216 547 279 547 353 c + +ce} _d +/E{573 0 87 0 542 702 sc +542 0 m +87 0 l +87 702 l +531 702 l +531 627 l +175 627 l +175 403 l +458 403 l +458 333 l +175 333 l +175 76 l +542 76 l +542 0 l + +ce} _d +/F{491 0 84 0 514 702 sc +514 627 m +172 627 l +172 403 l +456 403 l +456 333 l +172 333 l +172 0 l +84 0 l +84 702 l +514 702 l +514 627 l + +ce} _d +/G{675 0 49 -10 614 713 sc +614 -5 m +560 -5 l +537 82 l +497 24 436 -7 355 -10 c +350 -10 346 -10 342 -10 c +237 -10 157 35 104 125 c +67 187 49 260 49 344 c +49 452 77 541 133 610 c +188 679 262 713 353 713 c +457 713 532 670 579 585 c +591 563 600 538 607 511 c +524 490 l +512 553 480 597 428 622 c +403 633 376 639 347 639 c +256 639 195 589 164 488 c +151 447 144 400 144 348 c +144 251 167 176 212 123 c +247 82 292 61 348 61 c +418 61 469 88 500 141 c +516 170 524 203 524 242 c +524 281 l +349 281 l +349 354 l +614 354 l +614 -5 l + +ce} _d +/I{266 0 88 0 176 702 sc +176 0 m +88 0 l +88 702 l +176 702 l +176 0 l + +ce} _d +/J{409 0 17 -10 331 702 sc +331 229 m +331 104 290 29 207 2 c +182 -6 153 -10 120 -10 c +86 -10 52 -5 17 4 c +17 76 l +50 69 81 66 108 66 c +171 66 211 83 227 118 c +238 139 243 176 243 229 c +243 702 l +331 702 l +331 229 l + +ce} _d +/K{634 0 88 0 643 702 sc +643 0 m +546 0 l +337 387 l +176 187 l +176 0 l +88 0 l +88 702 l +176 702 l +176 295 l +493 702 l +588 702 l +398 457 l +643 0 l + +ce} _d +/L{512 0 86 0 501 702 sc +501 0 m +86 0 l +86 702 l +174 702 l +174 78 l +501 78 l +501 0 l + +ce} _d +/M{839 0 82 0 761 702 sc +761 0 m +673 0 l +673 613 l +669 613 l +446 0 l +387 0 l +160 613 l +156 613 l +156 0 l +82 0 l +82 702 l +213 702 l +425 140 l +632 702 l +761 702 l +761 0 l + +ce} _d +/N{675 0 84 0 601 702 sc +601 0 m +515 0 l +158 612 l +158 0 l +84 0 l +84 702 l +195 702 l +527 130 l +527 702 l +601 702 l +601 0 l + +ce} _d +/O{675 0 45 -10 623 713 sc +623 359 m +623 258 598 173 548 102 c +495 27 424 -10 335 -10 c +230 -10 151 36 98 128 c +63 189 45 262 45 346 c +45 453 71 540 124 609 c +176 678 246 713 334 713 c +435 713 513 669 566 580 c +604 517 623 443 623 359 c + +530 354 m +530 449 509 522 468 575 c +435 618 392 640 337 640 c +250 640 191 591 159 492 c +144 448 137 399 137 345 c +137 258 157 187 197 133 c +232 85 278 61 335 61 c +417 61 474 108 507 203 c +522 248 530 299 530 354 c + +ce} _d +/P{573 0 66 0 542 702 sc +542 492 m +542 436 523 388 485 348 c +480 343 l +441 305 385 286 311 286 c +154 286 l +154 0 l +66 0 l +66 702 l +301 702 l +376 702 433 686 470 655 c +510 622 534 575 541 515 c +542 507 542 499 542 492 c + +453 492 m +453 557 425 600 370 620 c +351 626 331 629 308 629 c +154 629 l +154 358 l +302 358 l +375 358 422 384 442 435 c +449 452 453 471 453 492 c + +ce} _d +/R{634 0 83 0 588 702 sc +588 0 m +496 0 l +366 304 l +171 304 l +171 0 l +83 0 l +83 702 l +346 702 l +436 702 502 676 544 624 c +563 599 575 568 580 532 c +581 524 581 515 581 506 c +581 445 559 396 515 359 c +496 344 474 333 450 326 c +588 0 l + +493 507 m +493 577 454 616 377 625 c +367 626 357 627 346 627 c +171 627 l +171 376 l +336 376 l +422 376 472 406 487 467 c +491 479 493 492 493 507 c + +ce} _d +/S{634 0 43 -10 590 713 sc +590 201 m +590 114 550 53 469 17 c +428 -1 381 -10 328 -10 c +184 -10 89 56 43 189 c +122 207 l +143 134 191 89 266 72 c +286 67 307 65 330 65 c +398 65 447 83 476 120 c +491 139 499 162 499 189 c +499 237 469 273 408 296 c +343 314 l +264 334 221 345 214 348 c +179 359 153 373 135 389 c +97 423 78 466 78 519 c +78 599 115 655 189 688 c +227 705 269 713 316 713 c +413 713 485 678 534 608 c +554 571 l +559 562 563 552 566 541 c +486 519 l +477 565 448 600 398 624 c +371 637 343 643 314 643 c +265 643 226 629 195 601 c +174 582 164 558 164 531 c +164 485 193 451 250 430 c +264 425 308 414 383 397 c +450 382 497 363 524 340 c +568 305 590 258 590 201 c + +ce} _d +/T{512 0 11 0 499 702 sc +499 626 m +299 626 l +299 0 l +211 0 l +211 626 l +11 626 l +11 702 l +499 702 l +499 626 l + +ce} _d +/U{655 0 83 -10 567 702 sc +567 258 m +567 184 556 128 534 91 c +528 83 522 75 516 68 c +473 16 410 -10 327 -10 c +210 -10 135 32 103 117 c +90 154 83 201 83 258 c +83 702 l +171 702 l +171 258 l +171 179 187 126 218 99 c +243 78 282 68 334 68 c +417 68 468 103 485 174 c +491 197 494 225 494 258 c +494 702 l +567 702 l +567 258 l + +ce} _d +/V{573 0 10 0 569 702 sc +569 702 m +332 0 l +248 0 l +10 702 l +102 702 l +298 123 l +493 702 l +569 702 l + +ce} _d +/X{552 0 9 0 552 702 sc +552 0 m +453 0 l +275 299 l +91 0 l +9 0 l +234 364 l +34 702 l +132 702 l +287 442 l +443 702 l +524 702 l +328 381 l +552 0 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-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /WenQuanYiZenHeiMono-0 def +/PaintType 0 def +/FontMatrix [0.0009765625 0 0 0.0009765625 0 0] def +/FontBBox [-129 -304 1076 986] def +/FontType 3 def +/Encoding [/W /e /n /Q /u /a /Y /i /space /Z /H /M /o /colon /A /B /C /D /E /F /G /I /J /K /L /N /O /P /R /S /T /U /V /X] def +/CharStrings 35 dict dup begin +/.notdef 0 def +/W{512 0 26 18 486 766 sc +157 141 m +159 141 l +214 664 l +306 664 l +361 141 l +364 141 l +410 766 l +486 766 l +425 18 l +313 18 l +257 551 l +255 551 l +199 18 l +87 18 l +26 766 l +111 766 l +157 141 l + +ce} _d +/e{512 0 56 8 445 561 sc +141 258 m +144 195 157 149 180 121 c +203 93 237 79 282 79 c +323 79 369 91 420 116 c +420 34 l +369 17 321 8 276 8 c +129 8 56 100 56 285 c +56 381 73 451 107 495 c +142 539 193 561 261 561 c +323 561 369 540 399 497 c +430 455 445 386 445 290 c +445 283 444 272 443 258 c +141 258 l + +141 326 m +365 326 l +364 435 330 490 261 490 c +222 490 193 478 174 453 c +155 429 144 387 141 326 c + +ce} _d +/n{512 0 72 18 451 561 sc +451 356 m +451 18 l +372 18 l +372 338 l +372 398 365 438 351 458 c +338 478 313 488 276 488 c +242 488 213 469 189 431 c +165 393 153 341 153 276 c +153 18 l +72 18 l +72 551 l +147 551 l +150 474 l +152 474 l +165 500 184 521 211 537 c +238 553 266 561 297 561 c +351 561 390 545 414 514 c +439 483 451 431 451 356 c + +ce} _d +/Q{512 0 41 -135 492 776 sc +93 689 m +128 747 183 776 256 776 c +329 776 383 747 418 689 c +453 632 471 533 471 392 c +471 206 437 89 369 40 c +369 38 l +397 23 422 1 443 -30 c +465 -61 481 -96 492 -135 c +401 -135 l +387 -82 369 -44 346 -23 c +323 -2 293 8 256 8 c +183 8 128 37 93 94 c +58 152 41 251 41 392 c +41 533 58 632 93 689 c + +183 108 m +202 91 226 82 256 82 c +286 82 310 91 328 108 c +347 125 361 157 372 203 c +383 250 389 313 389 392 c +389 471 383 534 372 580 c +361 627 347 659 328 676 c +310 693 286 702 256 702 c +226 702 202 693 183 676 c +165 659 150 627 139 580 c +128 534 123 471 123 392 c +123 313 128 250 139 203 c +150 157 165 125 183 108 c + +ce} _d +/u{512 0 67 8 435 551 sc +67 203 m +67 551 l +145 551 l +145 221 l +145 164 151 127 164 108 c +177 90 201 81 236 81 c +269 81 297 100 320 137 c +343 175 354 227 354 293 c +354 551 l +435 551 l +435 18 l +359 18 l +357 95 l +355 95 l +342 68 323 46 298 31 c +273 16 245 8 215 8 c +162 8 124 23 101 52 c +78 81 67 132 67 203 c + +ce} _d +/a{512 0 61 8 440 561 sc +261 561 m +330 561 377 547 402 520 c +427 493 440 442 440 367 c +440 18 l +367 18 l +365 95 l +362 95 l +330 37 279 8 210 8 c +165 8 129 22 102 50 c +75 79 61 118 61 167 c +61 229 82 277 124 310 c +166 344 229 361 312 361 c +361 361 l +361 387 l +361 426 353 453 338 469 c +323 485 298 493 261 493 c +238 493 210 489 175 480 c +140 472 111 463 87 452 c +87 525 l +111 536 140 544 174 551 c +208 558 237 561 261 561 c + +361 300 m +312 300 l +196 300 138 257 138 172 c +138 141 146 118 161 101 c +177 85 198 77 225 77 c +266 77 298 93 323 126 c +348 159 361 205 361 264 c +361 300 l + +ce} _d +/Y{512 0 31 18 481 766 sc +257 402 m +259 402 l +394 766 l +481 766 l +298 315 l +298 18 l +214 18 l +214 315 l +31 766 l +123 766 l +257 402 l + +ce} _d +/i{512 0 97 18 435 797 sc +324 551 m +324 88 l +435 88 l +435 18 l +97 18 l +97 88 l +240 88 l +240 481 l +128 481 l +128 551 l +324 551 l + +219 674 m +219 797 l +324 797 l +324 674 l +219 674 l + +ce} _d +/space{512 0 0 0 0 0 sc +ce} _d +/Z{512 0 77 18 435 766 sc +343 692 m +343 694 l +77 694 l +77 766 l +435 766 l +435 694 l +169 92 l +169 90 l +435 90 l +435 18 l +77 18 l +77 90 l +343 692 l + +ce} _d +/H{512 0 61 18 451 766 sc +143 766 m +143 461 l +365 461 l +365 766 l +451 766 l +451 18 l +365 18 l +365 387 l +143 387 l +143 18 l +61 18 l +61 766 l +143 766 l + +ce} _d +/M{512 0 41 18 471 766 sc +387 571 m +385 571 l +295 223 l +213 223 l +123 571 l +121 571 l +121 18 l +41 18 l +41 766 l +135 766 l +257 305 l +259 305 l +381 766 l +471 766 l +471 18 l +387 18 l +387 571 l + +ce} _d +/o{512 0 51 8 461 561 sc +51 284 m +51 469 119 561 256 561 c +393 561 461 469 461 284 c +461 100 393 8 256 8 c +119 8 51 100 51 284 c + +164 125 m +184 94 215 79 256 79 c +297 79 328 94 347 125 c +367 156 377 209 377 284 c +377 359 367 412 347 443 c +328 474 297 490 256 490 c +215 490 184 474 164 443 c +145 412 135 359 135 284 c +135 209 145 156 164 125 c + +ce} _d +/colon{512 0 195 18 317 571 sc +195 418 m +195 571 l +317 571 l +317 418 l +195 418 l + +195 18 m +195 172 l +317 172 l +317 18 l +195 18 l + +ce} _d +/A{512 0 20 18 492 766 sc +255 694 m +253 694 l +168 305 l +340 305 l +255 694 l + +356 233 m +152 233 l +104 18 l +20 18 l +205 766 l +307 766 l +492 18 l +403 18 l +356 233 l + +ce} _d +/B{512 0 77 8 466 776 sc +161 459 m +207 459 l +262 459 301 469 326 489 c +351 509 364 540 364 582 c +364 621 352 651 327 672 c +302 694 267 705 222 705 c +197 705 177 702 161 696 c +161 459 l + +161 387 m +161 88 l +186 83 217 80 253 80 c +339 80 382 135 382 244 c +382 339 327 387 217 387 c +161 387 l + +466 233 m +466 83 389 8 236 8 c +181 8 128 13 77 24 c +77 761 l +128 771 181 776 236 776 c +375 776 445 715 445 592 c +445 550 435 515 414 486 c +393 457 365 438 328 429 c +328 427 l +367 420 400 398 426 361 c +453 325 466 282 466 233 c + +ce} _d +/C{512 0 56 8 435 776 sc +56 392 m +56 527 77 624 118 685 c +159 746 221 776 302 776 c +347 776 390 766 430 745 c +430 669 l +389 691 348 702 307 702 c +194 702 138 599 138 392 c +138 280 152 200 181 153 c +210 106 252 82 307 82 c +350 82 392 95 435 121 c +435 39 l +395 18 351 8 302 8 c +219 8 157 37 116 96 c +76 155 56 253 56 392 c + +ce} _d +/D{512 0 67 8 476 776 sc +392 392 m +392 507 377 587 347 633 c +318 679 271 702 207 702 c +184 702 166 699 151 694 c +151 90 l +166 85 184 82 207 82 c +251 82 286 90 311 107 c +337 124 357 155 371 200 c +385 246 392 310 392 392 c + +476 392 m +476 251 454 151 411 94 c +368 37 300 8 207 8 c +159 8 112 13 67 24 c +67 761 l +112 771 159 776 207 776 c +300 776 368 747 411 688 c +454 630 476 531 476 392 c + +ce} _d +/E{512 0 82 18 430 766 sc +166 692 m +166 459 l +420 459 l +420 387 l +166 387 l +166 92 l +430 92 l +430 18 l +82 18 l +82 766 l +430 766 l +430 692 l +166 692 l + +ce} _d +/F{512 0 92 18 430 766 sc +176 387 m +176 18 l +92 18 l +92 766 l +430 766 l +430 692 l +176 692 l +176 459 l +420 459 l +420 387 l +176 387 l + +ce} _d +/G{512 0 41 8 461 776 sc +379 105 m +379 387 l +220 387 l +220 459 l +461 459 l +461 49 l +406 22 348 8 287 8 c +206 8 145 38 103 99 c +62 160 41 257 41 392 c +41 526 63 623 106 684 c +149 745 215 776 302 776 c +342 776 386 768 435 751 c +435 672 l +390 692 346 702 302 702 c +243 702 198 677 167 628 c +136 579 121 501 121 392 c +121 185 178 82 292 82 c +323 82 352 90 379 105 c + +ce} _d +/I{512 0 92 18 420 766 sc +420 18 m +92 18 l +92 90 l +213 90 l +213 694 l +92 694 l +92 766 l +420 766 l +420 694 l +299 694 l +299 90 l +420 90 l +420 18 l + +ce} _d +/J{512 0 61 8 410 766 sc +410 766 m +410 213 l +410 138 395 85 365 54 c +336 23 286 8 215 8 c +159 8 108 18 61 39 c +61 128 l +81 117 107 106 138 96 c +170 87 196 82 215 82 c +251 82 278 92 296 113 c +314 134 323 168 323 215 c +323 694 l +154 694 l +154 766 l +410 766 l + +ce} _d +/K{512 0 77 18 476 766 sc +161 428 m +163 428 l +374 766 l +471 766 l +241 408 l +476 18 l +379 18 l +163 387 l +161 387 l +161 18 l +77 18 l +77 766 l +161 766 l +161 428 l + +ce} _d +/L{512 0 102 18 430 766 sc +186 766 m +186 92 l +430 92 l +430 18 l +102 18 l +102 766 l +186 766 l + +ce} _d +/N{512 0 67 18 445 766 sc +155 582 m +153 582 l +153 18 l +67 18 l +67 766 l +153 766 l +361 203 l +364 203 l +364 766 l +445 766 l +445 18 l +364 18 l +155 582 l + +ce} _d +/O{512 0 41 8 471 776 sc +93 689 m +128 747 183 776 256 776 c +329 776 383 747 418 689 c +453 632 471 533 471 392 c +471 251 453 152 418 94 c +383 37 329 8 256 8 c +183 8 128 37 93 94 c +58 152 41 251 41 392 c +41 533 58 632 93 689 c + +183 108 m +202 91 226 82 256 82 c +286 82 310 91 328 108 c +347 125 361 157 372 203 c +383 250 389 313 389 392 c +389 471 383 534 372 580 c +361 627 347 659 328 676 c +310 693 286 702 256 702 c +226 702 202 693 183 676 c +165 659 150 627 139 580 c +128 534 123 471 123 392 c +123 313 128 250 139 203 c +150 157 165 125 183 108 c + +ce} _d +/P{512 0 77 18 466 776 sc +384 551 m +384 605 372 644 347 668 c +322 693 284 705 232 705 c +204 705 180 702 161 696 c +161 397 l +181 394 205 392 232 392 c +285 392 323 404 347 428 c +372 453 384 494 384 551 c + +466 551 m +466 469 448 410 412 374 c +376 339 320 321 243 321 c +219 321 192 323 161 326 c +161 18 l +77 18 l +77 761 l +130 771 185 776 241 776 c +318 776 375 758 411 722 c +448 687 466 630 466 551 c + +ce} _d +/R{512 0 72 18 481 776 sc +379 571 m +379 660 328 705 227 705 c +199 705 175 702 156 696 c +156 418 l +217 418 l +276 418 318 429 342 452 c +367 475 379 514 379 571 c + +156 346 m +156 18 l +72 18 l +72 761 l +125 771 180 776 236 776 c +312 776 368 759 405 725 c +442 692 461 640 461 571 c +461 474 424 408 349 374 c +349 372 l +370 361 393 317 417 238 c +481 18 l +393 18 l +333 240 l +321 283 307 312 290 325 c +274 339 246 346 207 346 c +156 346 l + +ce} _d +/S{512 0 72 8 451 776 sc +266 702 m +234 702 208 692 187 671 c +166 650 156 624 156 592 c +156 558 163 530 178 507 c +193 485 217 466 251 451 c +327 417 379 382 408 345 c +437 309 451 262 451 203 c +451 138 433 90 398 57 c +363 24 312 8 246 8 c +184 8 128 27 77 65 c +77 162 l +132 109 190 82 251 82 c +328 82 367 122 367 203 c +367 240 358 271 340 296 c +322 321 292 342 251 361 c +187 390 141 422 113 459 c +86 496 72 540 72 592 c +72 647 89 691 124 725 c +159 759 204 776 261 776 c +297 776 327 773 350 768 c +373 763 400 752 430 735 c +430 643 l +377 682 323 702 266 702 c + +ce} _d +/T{512 0 56 18 456 766 sc +214 18 m +214 694 l +56 694 l +56 766 l +456 766 l +456 694 l +298 694 l +298 18 l +214 18 l + +ce} _d +/U{512 0 61 8 451 766 sc +402 58 m +369 25 321 8 256 8 c +191 8 143 25 110 58 c +77 91 61 143 61 213 c +61 766 l +147 766 l +147 233 l +147 178 156 139 174 116 c +193 93 221 82 258 82 c +295 82 323 93 341 116 c +360 139 369 178 369 233 c +369 766 l +451 766 l +451 213 l +451 143 435 91 402 58 c + +ce} _d +/V{512 0 31 18 481 766 sc +259 90 m +397 766 l +481 766 l +307 18 l +205 18 l +31 766 l +119 766 l +257 90 l +259 90 l + +ce} _d +/X{512 0 51 18 461 766 sc +257 469 m +259 469 l +374 766 l +459 766 l +307 402 l +461 18 l +369 18 l +255 331 l +253 331 l +138 18 l +51 18 l +205 402 l +53 766 l +143 766 l +257 469 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 +0 0 translate +0 0 504 72 rectclip +gsave +0 0 m +504 0 l +504 72 l +0 72 l +cl +1 setgray +fill +grestore +gsave +0 36 m +504 36 l +504 72 l +0 72 l +0 36 l +cl +grestore +0 setgray +/WenQuanYiZenHei-0 16.000 selectfont +gsave + +55.4375 49.2031 translate +0 rotate +0 0 m /W glyphshow +13.1094 0 m /e glyphshow +21.7344 0 m /n glyphshow +30.3594 0 m /Q glyphshow +40.9062 0 m /u glyphshow +49.5312 0 m /a glyphshow +58.1562 0 m /n glyphshow +66.7812 0 m /Y glyphshow +75.7344 0 m /i glyphshow +79.5625 0 m /space glyphshow +84.3594 0 m /Z glyphshow +92.9844 0 m /e glyphshow +101.609 0 m /n glyphshow +110.234 0 m /space glyphshow +115.031 0 m /H glyphshow +125.578 0 m /e glyphshow +134.203 0 m /i glyphshow +138.031 0 m /colon glyphshow +142.828 0 m /space glyphshow +147.625 0 m /A glyphshow +156.578 0 m /B glyphshow +166.484 0 m /C glyphshow +176.391 0 m /D glyphshow +186.938 0 m /E glyphshow +195.891 0 m /F glyphshow +203.562 0 m /G glyphshow +214.109 0 m /H glyphshow +224.656 0 m /I glyphshow +228.812 0 m /J glyphshow +235.203 0 m /K glyphshow +245.109 0 m /L glyphshow +253.109 0 m /M glyphshow +266.219 0 m /N glyphshow +276.766 0 m /O glyphshow +287.312 0 m /P glyphshow +296.266 0 m /Q glyphshow +306.812 0 m /R glyphshow +316.719 0 m /S glyphshow +326.625 0 m /T glyphshow +334.625 0 m /U glyphshow +344.859 0 m /V glyphshow +353.812 0 m /W glyphshow +366.922 0 m /X glyphshow +375.547 0 m /Y glyphshow +384.5 0 m /Z glyphshow +grestore +gsave +0 0 m +504 0 l +504 36 l +0 36 l +0 0 l +cl +grestore +/WenQuanYiZenHeiMono-0 16.000 selectfont +gsave + +52 13.2031 translate +0 rotate +0 0 m /W glyphshow +8 0 m /e glyphshow +16 0 m /n glyphshow +24 0 m /Q glyphshow +32 0 m /u glyphshow +40 0 m /a glyphshow +48 0 m /n glyphshow +56 0 m /Y glyphshow +64 0 m /i glyphshow +72 0 m /space glyphshow +80 0 m /Z glyphshow +88 0 m /e glyphshow +96 0 m /n glyphshow +104 0 m /space glyphshow +112 0 m /H glyphshow +120 0 m /e glyphshow +128 0 m /i glyphshow +136 0 m /space glyphshow +144 0 m /M glyphshow +152 0 m /o glyphshow +160 0 m /n glyphshow +168 0 m /o glyphshow +176 0 m /colon glyphshow +184 0 m /space glyphshow +192 0 m /A glyphshow +200 0 m /B glyphshow +208 0 m /C glyphshow +216 0 m /D glyphshow +224 0 m /E glyphshow +232 0 m /F glyphshow +240 0 m /G glyphshow +248 0 m /H glyphshow +256 0 m /I glyphshow +264 0 m /J glyphshow +272 0 m /K glyphshow +280 0 m /L glyphshow +288 0 m /M glyphshow +296 0 m /N glyphshow +304 0 m /O glyphshow +312 0 m /P glyphshow +320 0 m /Q glyphshow +328 0 m /R glyphshow +336 0 m /S glyphshow +344 0 m /T glyphshow +352 0 m /U glyphshow +360 0 m /V glyphshow +368 0 m /W glyphshow +376 0 m /X glyphshow +384 0 m /Y glyphshow +392 0 m /Z glyphshow +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type42.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type42.eps new file mode 100644 index 000000000000..94c59cb556a8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/ttc_type42.eps @@ -0,0 +1,1483 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: ttc_type42.eps +%%Creator: Matplotlib v3.11.0.dev2075+g5a13dc378e, https://matplotlib.org/ +%%CreationDate: Fri Mar 13 23:13:37 2026 +%%Orientation: portrait +%%BoundingBox: 0 0 504 72 +%%HiResBoundingBox: 0.000000 0.000000 504.000000 72.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 /WenQuanYiZenHei-0 def +/PaintType 0 def +/FontMatrix [0.0009765625 0 0 0.0009765625 0 0] def +/FontBBox [-129 -304 1076 986] def +/FontType 3 def +/Encoding [/W /e /n /Q /u /a /Y /i /space /Z /H /colon /A /B /C /D /E /F /G /I /J /K /L /M /N /O /P /R /S /T /U /V /X] def +/CharStrings 34 dict dup begin +/.notdef 0 def +/W{839 0 11 0 831 702 sc +831 702 m +663 0 l +574 0 l +422 545 l +279 0 l +189 0 l +11 702 l +101 702 l +242 133 l +244 133 l +392 702 l +463 702 l +623 133 l +625 133 l +755 702 l +831 702 l + +ce} _d +/e{552 0 38 -10 506 534 sc +506 254 m +128 254 l +127 187 143 136 174 101 c +200 72 236 57 283 57 c +341 57 384 82 411 133 c +415 140 419 149 422 158 c +498 142 l +479 82 439 38 378 11 c +346 -3 312 -10 276 -10 c +187 -10 121 27 78 100 c +51 145 38 199 38 260 c +38 346 64 415 116 468 c +159 512 213 534 279 534 c +369 534 434 495 473 417 c +495 374 506 323 506 266 c +506 254 l + +418 313 m +419 370 401 413 366 442 c +342 462 313 472 279 472 c +226 472 186 448 158 400 c +142 374 133 345 132 313 c +418 313 l + +ce} _d +/n{552 0 71 0 482 534 sc +482 0 m +402 0 l +402 322 l +402 366 398 396 391 412 c +390 414 389 416 388 418 c +373 444 348 459 313 464 c +308 465 304 465 299 465 c +234 465 190 432 166 366 c +156 337 151 306 151 272 c +151 0 l +71 0 l +71 520 l +146 520 l +146 424 l +148 424 l +173 477 211 511 263 526 c +278 531 294 534 310 534 c +375 534 423 508 455 457 c +458 453 l +474 425 482 377 482 309 c +482 0 l + +ce} _d +/Q{675 0 42 -167 626 713 sc +626 351 m +626 244 599 158 546 91 c +509 46 462 16 407 1 c +407 -14 l +407 -55 425 -80 461 -88 c +468 -90 476 -91 485 -91 c +500 -91 532 -89 580 -84 c +580 -154 l +553 -163 528 -167 504 -167 c +412 -167 357 -130 340 -55 c +337 -41 335 -26 335 -10 c +224 -7 142 41 91 135 c +58 195 42 265 42 346 c +42 456 69 545 124 613 c +177 680 247 713 334 713 c +441 713 520 666 572 572 c +608 509 626 436 626 351 c + +530 349 m +530 482 496 569 428 610 c +401 627 370 635 333 635 c +234 635 172 576 147 459 c +140 424 136 386 136 344 c +136 239 160 161 207 112 c +238 79 278 62 327 62 c +425 62 488 116 516 225 c +525 263 530 304 530 349 c + +ce} _d +/u{552 0 71 -10 479 520 sc +479 0 m +407 0 l +407 103 l +404 103 l +386 58 355 25 310 4 c +289 -5 268 -10 245 -10 c +144 -10 87 45 74 156 c +72 171 71 187 71 204 c +71 520 l +151 520 l +151 204 l +151 113 181 65 242 59 c +242 59 245 59 252 59 c +311 59 354 89 380 148 c +393 177 399 209 399 244 c +399 520 l +479 520 l +479 0 l + +ce} _d +/a{552 0 56 -10 509 534 sc +509 0 m +429 0 l +420 97 l +385 26 324 -10 238 -10 c +171 -10 120 11 87 53 c +66 79 56 110 56 147 c +56 198 78 240 122 273 c +131 281 142 287 153 292 c +198 313 272 324 375 323 c +420 323 l +420 345 l +420 409 397 448 352 463 c +316 470 l +307 471 298 471 288 471 c +205 471 158 440 145 379 c +71 391 l +80 458 124 502 205 522 c +233 530 263 534 295 534 c +384 534 442 510 469 463 c +488 431 498 380 498 311 c +498 110 l +498 63 502 26 509 0 c + +420 228 m +420 262 l +353 262 l +212 262 142 222 142 143 c +142 100 165 71 211 58 c +224 54 239 52 255 52 c +312 52 356 76 388 123 c +409 154 420 189 420 228 c + +ce} _d +/Y{573 0 11 0 568 702 sc +568 702 m +334 296 l +334 0 l +246 0 l +246 296 l +11 702 l +114 702 l +300 379 l +488 702 l +568 702 l + +ce} _d +/i{245 0 79 0 167 702 sc +167 612 m +79 612 l +79 702 l +167 702 l +167 612 l + +163 0 m +83 0 l +83 520 l +163 520 l +163 0 l + +ce} _d +/space{307 0 0 0 0 0 sc +ce} _d +/Z{552 0 17 0 513 702 sc +513 0 m +17 0 l +17 76 l +399 630 l +35 630 l +35 702 l +502 702 l +502 644 l +116 76 l +513 76 l +513 0 l + +ce} _d +/H{675 0 83 0 585 702 sc +585 0 m +497 0 l +497 334 l +171 334 l +171 0 l +83 0 l +83 702 l +171 702 l +171 411 l +497 411 l +497 702 l +585 702 l +585 0 l + +ce} _d +/colon{307 0 101 0 215 520 sc +215 404 m +101 404 l +101 520 l +215 520 l +215 404 l + +215 0 m +101 0 l +101 116 l +215 116 l +215 0 l + +ce} _d +/A{573 0 11 0 568 702 sc +568 0 m +478 0 l +408 205 l +147 205 l +85 0 l +11 0 l +239 702 l +340 702 l +568 0 l + +388 271 m +281 608 l +172 271 l +388 271 l + +ce} _d +/B{634 0 83 0 588 702 sc +588 194 m +588 130 565 80 520 45 c +484 16 434 1 370 0 c +347 0 l +83 0 l +83 702 l +348 702 l +405 702 448 694 477 679 c +482 676 487 673 493 670 c +541 637 565 591 566 531 c +566 470 542 424 494 394 c +462 380 l +456 377 449 375 442 374 c +442 372 l +501 359 543 327 568 276 c +581 251 588 224 588 194 c + +479 520 m +479 585 443 621 370 630 c +361 631 351 631 341 631 c +171 631 l +171 401 l +317 401 l +425 401 479 441 479 520 c + +500 198 m +500 241 485 276 454 303 c +453 304 451 306 449 307 c +426 325 389 334 338 334 c +171 334 l +171 75 l +343 75 l +432 75 483 105 497 166 c +499 175 500 186 500 198 c + +ce} _d +/C{634 0 43 -10 589 713 sc +589 219 m +558 90 490 16 386 -5 c +367 -8 348 -10 329 -10 c +224 -10 146 38 94 135 c +60 199 43 273 43 358 c +43 471 72 560 131 626 c +183 684 251 713 336 713 c +435 713 508 669 555 582 c +570 554 582 523 589 488 c +506 473 l +479 573 430 628 359 637 c +350 638 342 639 333 639 c +248 639 190 590 159 492 c +146 449 139 402 139 351 c +139 261 158 189 197 134 c +230 87 274 63 329 63 c +418 63 477 117 506 225 c +507 229 508 233 509 237 c +589 219 l + +ce} _d +/D{675 0 87 0 636 702 sc +636 353 m +636 247 607 160 550 93 c +496 31 425 0 338 0 c +87 0 l +87 702 l +309 702 l +394 702 462 682 512 642 c +525 631 538 618 551 603 c +608 537 636 454 636 353 c + +547 353 m +547 436 525 504 482 557 c +449 599 403 623 344 628 c +304 629 l +175 629 l +175 75 l +304 75 l +382 75 440 97 478 140 c +484 147 490 155 496 164 c +530 216 547 279 547 353 c + +ce} _d +/E{573 0 87 0 542 702 sc +542 0 m +87 0 l +87 702 l +531 702 l +531 627 l +175 627 l +175 403 l +458 403 l +458 333 l +175 333 l +175 76 l +542 76 l +542 0 l + +ce} _d +/F{491 0 84 0 514 702 sc +514 627 m +172 627 l +172 403 l +456 403 l +456 333 l +172 333 l +172 0 l +84 0 l +84 702 l +514 702 l +514 627 l + +ce} _d +/G{675 0 49 -10 614 713 sc +614 -5 m +560 -5 l +537 82 l +497 24 436 -7 355 -10 c +350 -10 346 -10 342 -10 c +237 -10 157 35 104 125 c +67 187 49 260 49 344 c +49 452 77 541 133 610 c +188 679 262 713 353 713 c +457 713 532 670 579 585 c +591 563 600 538 607 511 c +524 490 l +512 553 480 597 428 622 c +403 633 376 639 347 639 c +256 639 195 589 164 488 c +151 447 144 400 144 348 c +144 251 167 176 212 123 c +247 82 292 61 348 61 c +418 61 469 88 500 141 c +516 170 524 203 524 242 c +524 281 l +349 281 l +349 354 l +614 354 l +614 -5 l + +ce} _d +/I{266 0 88 0 176 702 sc +176 0 m +88 0 l +88 702 l +176 702 l +176 0 l + +ce} _d +/J{409 0 17 -10 331 702 sc +331 229 m +331 104 290 29 207 2 c +182 -6 153 -10 120 -10 c +86 -10 52 -5 17 4 c +17 76 l +50 69 81 66 108 66 c +171 66 211 83 227 118 c +238 139 243 176 243 229 c +243 702 l +331 702 l +331 229 l + +ce} _d +/K{634 0 88 0 643 702 sc +643 0 m +546 0 l +337 387 l +176 187 l +176 0 l +88 0 l +88 702 l +176 702 l +176 295 l +493 702 l +588 702 l +398 457 l +643 0 l + +ce} _d +/L{512 0 86 0 501 702 sc +501 0 m +86 0 l +86 702 l +174 702 l +174 78 l +501 78 l +501 0 l + +ce} _d +/M{839 0 82 0 761 702 sc +761 0 m +673 0 l +673 613 l +669 613 l +446 0 l +387 0 l +160 613 l +156 613 l +156 0 l +82 0 l +82 702 l +213 702 l +425 140 l +632 702 l +761 702 l +761 0 l + +ce} _d +/N{675 0 84 0 601 702 sc +601 0 m +515 0 l +158 612 l +158 0 l +84 0 l +84 702 l +195 702 l +527 130 l +527 702 l +601 702 l +601 0 l + +ce} _d +/O{675 0 45 -10 623 713 sc +623 359 m +623 258 598 173 548 102 c +495 27 424 -10 335 -10 c +230 -10 151 36 98 128 c +63 189 45 262 45 346 c +45 453 71 540 124 609 c +176 678 246 713 334 713 c +435 713 513 669 566 580 c +604 517 623 443 623 359 c + +530 354 m +530 449 509 522 468 575 c +435 618 392 640 337 640 c +250 640 191 591 159 492 c +144 448 137 399 137 345 c +137 258 157 187 197 133 c +232 85 278 61 335 61 c +417 61 474 108 507 203 c +522 248 530 299 530 354 c + +ce} _d +/P{573 0 66 0 542 702 sc +542 492 m +542 436 523 388 485 348 c +480 343 l +441 305 385 286 311 286 c +154 286 l +154 0 l +66 0 l +66 702 l +301 702 l +376 702 433 686 470 655 c +510 622 534 575 541 515 c +542 507 542 499 542 492 c + +453 492 m +453 557 425 600 370 620 c +351 626 331 629 308 629 c +154 629 l +154 358 l +302 358 l +375 358 422 384 442 435 c +449 452 453 471 453 492 c + +ce} _d +/R{634 0 83 0 588 702 sc +588 0 m +496 0 l +366 304 l +171 304 l +171 0 l +83 0 l +83 702 l +346 702 l +436 702 502 676 544 624 c +563 599 575 568 580 532 c +581 524 581 515 581 506 c +581 445 559 396 515 359 c +496 344 474 333 450 326 c +588 0 l + +493 507 m +493 577 454 616 377 625 c +367 626 357 627 346 627 c +171 627 l +171 376 l +336 376 l +422 376 472 406 487 467 c +491 479 493 492 493 507 c + +ce} _d +/S{634 0 43 -10 590 713 sc +590 201 m +590 114 550 53 469 17 c +428 -1 381 -10 328 -10 c +184 -10 89 56 43 189 c +122 207 l +143 134 191 89 266 72 c +286 67 307 65 330 65 c +398 65 447 83 476 120 c +491 139 499 162 499 189 c +499 237 469 273 408 296 c +343 314 l +264 334 221 345 214 348 c +179 359 153 373 135 389 c +97 423 78 466 78 519 c +78 599 115 655 189 688 c +227 705 269 713 316 713 c +413 713 485 678 534 608 c +554 571 l +559 562 563 552 566 541 c +486 519 l +477 565 448 600 398 624 c +371 637 343 643 314 643 c +265 643 226 629 195 601 c +174 582 164 558 164 531 c +164 485 193 451 250 430 c +264 425 308 414 383 397 c +450 382 497 363 524 340 c +568 305 590 258 590 201 c + +ce} _d +/T{512 0 11 0 499 702 sc +499 626 m +299 626 l +299 0 l +211 0 l +211 626 l +11 626 l +11 702 l +499 702 l +499 626 l + +ce} _d +/U{655 0 83 -10 567 702 sc +567 258 m +567 184 556 128 534 91 c +528 83 522 75 516 68 c +473 16 410 -10 327 -10 c +210 -10 135 32 103 117 c +90 154 83 201 83 258 c +83 702 l +171 702 l +171 258 l +171 179 187 126 218 99 c +243 78 282 68 334 68 c +417 68 468 103 485 174 c +491 197 494 225 494 258 c +494 702 l +567 702 l +567 258 l + +ce} _d +/V{573 0 10 0 569 702 sc +569 702 m +332 0 l +248 0 l +10 702 l +102 702 l +298 123 l +493 702 l +569 702 l + +ce} _d +/X{552 0 9 0 552 702 sc +552 0 m +453 0 l +275 299 l +91 0 l +9 0 l +234 364 l +34 702 l +132 702 l +287 442 l +443 702 l +524 702 l +328 381 l +552 0 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-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /WenQuanYiZenHeiMono-0 def +/PaintType 0 def +/FontMatrix [0.0009765625 0 0 0.0009765625 0 0] def +/FontBBox [-129 -304 1076 986] def +/FontType 3 def +/Encoding [/W /e /n /Q /u /a /Y /i /space /Z /H /M /o /colon /A /B /C /D /E /F /G /I /J /K /L /N /O /P /R /S /T /U /V /X] def +/CharStrings 35 dict dup begin +/.notdef 0 def +/W{512 0 26 18 486 766 sc +157 141 m +159 141 l +214 664 l +306 664 l +361 141 l +364 141 l +410 766 l +486 766 l +425 18 l +313 18 l +257 551 l +255 551 l +199 18 l +87 18 l +26 766 l +111 766 l +157 141 l + +ce} _d +/e{512 0 56 8 445 561 sc +141 258 m +144 195 157 149 180 121 c +203 93 237 79 282 79 c +323 79 369 91 420 116 c +420 34 l +369 17 321 8 276 8 c +129 8 56 100 56 285 c +56 381 73 451 107 495 c +142 539 193 561 261 561 c +323 561 369 540 399 497 c +430 455 445 386 445 290 c +445 283 444 272 443 258 c +141 258 l + +141 326 m +365 326 l +364 435 330 490 261 490 c +222 490 193 478 174 453 c +155 429 144 387 141 326 c + +ce} _d +/n{512 0 72 18 451 561 sc +451 356 m +451 18 l +372 18 l +372 338 l +372 398 365 438 351 458 c +338 478 313 488 276 488 c +242 488 213 469 189 431 c +165 393 153 341 153 276 c +153 18 l +72 18 l +72 551 l +147 551 l +150 474 l +152 474 l +165 500 184 521 211 537 c +238 553 266 561 297 561 c +351 561 390 545 414 514 c +439 483 451 431 451 356 c + +ce} _d +/Q{512 0 41 -135 492 776 sc +93 689 m +128 747 183 776 256 776 c +329 776 383 747 418 689 c +453 632 471 533 471 392 c +471 206 437 89 369 40 c +369 38 l +397 23 422 1 443 -30 c +465 -61 481 -96 492 -135 c +401 -135 l +387 -82 369 -44 346 -23 c +323 -2 293 8 256 8 c +183 8 128 37 93 94 c +58 152 41 251 41 392 c +41 533 58 632 93 689 c + +183 108 m +202 91 226 82 256 82 c +286 82 310 91 328 108 c +347 125 361 157 372 203 c +383 250 389 313 389 392 c +389 471 383 534 372 580 c +361 627 347 659 328 676 c +310 693 286 702 256 702 c +226 702 202 693 183 676 c +165 659 150 627 139 580 c +128 534 123 471 123 392 c +123 313 128 250 139 203 c +150 157 165 125 183 108 c + +ce} _d +/u{512 0 67 8 435 551 sc +67 203 m +67 551 l +145 551 l +145 221 l +145 164 151 127 164 108 c +177 90 201 81 236 81 c +269 81 297 100 320 137 c +343 175 354 227 354 293 c +354 551 l +435 551 l +435 18 l +359 18 l +357 95 l +355 95 l +342 68 323 46 298 31 c +273 16 245 8 215 8 c +162 8 124 23 101 52 c +78 81 67 132 67 203 c + +ce} _d +/a{512 0 61 8 440 561 sc +261 561 m +330 561 377 547 402 520 c +427 493 440 442 440 367 c +440 18 l +367 18 l +365 95 l +362 95 l +330 37 279 8 210 8 c +165 8 129 22 102 50 c +75 79 61 118 61 167 c +61 229 82 277 124 310 c +166 344 229 361 312 361 c +361 361 l +361 387 l +361 426 353 453 338 469 c +323 485 298 493 261 493 c +238 493 210 489 175 480 c +140 472 111 463 87 452 c +87 525 l +111 536 140 544 174 551 c +208 558 237 561 261 561 c + +361 300 m +312 300 l +196 300 138 257 138 172 c +138 141 146 118 161 101 c +177 85 198 77 225 77 c +266 77 298 93 323 126 c +348 159 361 205 361 264 c +361 300 l + +ce} _d +/Y{512 0 31 18 481 766 sc +257 402 m +259 402 l +394 766 l +481 766 l +298 315 l +298 18 l +214 18 l +214 315 l +31 766 l +123 766 l +257 402 l + +ce} _d +/i{512 0 97 18 435 797 sc +324 551 m +324 88 l +435 88 l +435 18 l +97 18 l +97 88 l +240 88 l +240 481 l +128 481 l +128 551 l +324 551 l + +219 674 m +219 797 l +324 797 l +324 674 l +219 674 l + +ce} _d +/space{512 0 0 0 0 0 sc +ce} _d +/Z{512 0 77 18 435 766 sc +343 692 m +343 694 l +77 694 l +77 766 l +435 766 l +435 694 l +169 92 l +169 90 l +435 90 l +435 18 l +77 18 l +77 90 l +343 692 l + +ce} _d +/H{512 0 61 18 451 766 sc +143 766 m +143 461 l +365 461 l +365 766 l +451 766 l +451 18 l +365 18 l +365 387 l +143 387 l +143 18 l +61 18 l +61 766 l +143 766 l + +ce} _d +/M{512 0 41 18 471 766 sc +387 571 m +385 571 l +295 223 l +213 223 l +123 571 l +121 571 l +121 18 l +41 18 l +41 766 l +135 766 l +257 305 l +259 305 l +381 766 l +471 766 l +471 18 l +387 18 l +387 571 l + +ce} _d +/o{512 0 51 8 461 561 sc +51 284 m +51 469 119 561 256 561 c +393 561 461 469 461 284 c +461 100 393 8 256 8 c +119 8 51 100 51 284 c + +164 125 m +184 94 215 79 256 79 c +297 79 328 94 347 125 c +367 156 377 209 377 284 c +377 359 367 412 347 443 c +328 474 297 490 256 490 c +215 490 184 474 164 443 c +145 412 135 359 135 284 c +135 209 145 156 164 125 c + +ce} _d +/colon{512 0 195 18 317 571 sc +195 418 m +195 571 l +317 571 l +317 418 l +195 418 l + +195 18 m +195 172 l +317 172 l +317 18 l +195 18 l + +ce} _d +/A{512 0 20 18 492 766 sc +255 694 m +253 694 l +168 305 l +340 305 l +255 694 l + +356 233 m +152 233 l +104 18 l +20 18 l +205 766 l +307 766 l +492 18 l +403 18 l +356 233 l + +ce} _d +/B{512 0 77 8 466 776 sc +161 459 m +207 459 l +262 459 301 469 326 489 c +351 509 364 540 364 582 c +364 621 352 651 327 672 c +302 694 267 705 222 705 c +197 705 177 702 161 696 c +161 459 l + +161 387 m +161 88 l +186 83 217 80 253 80 c +339 80 382 135 382 244 c +382 339 327 387 217 387 c +161 387 l + +466 233 m +466 83 389 8 236 8 c +181 8 128 13 77 24 c +77 761 l +128 771 181 776 236 776 c +375 776 445 715 445 592 c +445 550 435 515 414 486 c +393 457 365 438 328 429 c +328 427 l +367 420 400 398 426 361 c +453 325 466 282 466 233 c + +ce} _d +/C{512 0 56 8 435 776 sc +56 392 m +56 527 77 624 118 685 c +159 746 221 776 302 776 c +347 776 390 766 430 745 c +430 669 l +389 691 348 702 307 702 c +194 702 138 599 138 392 c +138 280 152 200 181 153 c +210 106 252 82 307 82 c +350 82 392 95 435 121 c +435 39 l +395 18 351 8 302 8 c +219 8 157 37 116 96 c +76 155 56 253 56 392 c + +ce} _d +/D{512 0 67 8 476 776 sc +392 392 m +392 507 377 587 347 633 c +318 679 271 702 207 702 c +184 702 166 699 151 694 c +151 90 l +166 85 184 82 207 82 c +251 82 286 90 311 107 c +337 124 357 155 371 200 c +385 246 392 310 392 392 c + +476 392 m +476 251 454 151 411 94 c +368 37 300 8 207 8 c +159 8 112 13 67 24 c +67 761 l +112 771 159 776 207 776 c +300 776 368 747 411 688 c +454 630 476 531 476 392 c + +ce} _d +/E{512 0 82 18 430 766 sc +166 692 m +166 459 l +420 459 l +420 387 l +166 387 l +166 92 l +430 92 l +430 18 l +82 18 l +82 766 l +430 766 l +430 692 l +166 692 l + +ce} _d +/F{512 0 92 18 430 766 sc +176 387 m +176 18 l +92 18 l +92 766 l +430 766 l +430 692 l +176 692 l +176 459 l +420 459 l +420 387 l +176 387 l + +ce} _d +/G{512 0 41 8 461 776 sc +379 105 m +379 387 l +220 387 l +220 459 l +461 459 l +461 49 l +406 22 348 8 287 8 c +206 8 145 38 103 99 c +62 160 41 257 41 392 c +41 526 63 623 106 684 c +149 745 215 776 302 776 c +342 776 386 768 435 751 c +435 672 l +390 692 346 702 302 702 c +243 702 198 677 167 628 c +136 579 121 501 121 392 c +121 185 178 82 292 82 c +323 82 352 90 379 105 c + +ce} _d +/I{512 0 92 18 420 766 sc +420 18 m +92 18 l +92 90 l +213 90 l +213 694 l +92 694 l +92 766 l +420 766 l +420 694 l +299 694 l +299 90 l +420 90 l +420 18 l + +ce} _d +/J{512 0 61 8 410 766 sc +410 766 m +410 213 l +410 138 395 85 365 54 c +336 23 286 8 215 8 c +159 8 108 18 61 39 c +61 128 l +81 117 107 106 138 96 c +170 87 196 82 215 82 c +251 82 278 92 296 113 c +314 134 323 168 323 215 c +323 694 l +154 694 l +154 766 l +410 766 l + +ce} _d +/K{512 0 77 18 476 766 sc +161 428 m +163 428 l +374 766 l +471 766 l +241 408 l +476 18 l +379 18 l +163 387 l +161 387 l +161 18 l +77 18 l +77 766 l +161 766 l +161 428 l + +ce} _d +/L{512 0 102 18 430 766 sc +186 766 m +186 92 l +430 92 l +430 18 l +102 18 l +102 766 l +186 766 l + +ce} _d +/N{512 0 67 18 445 766 sc +155 582 m +153 582 l +153 18 l +67 18 l +67 766 l +153 766 l +361 203 l +364 203 l +364 766 l +445 766 l +445 18 l +364 18 l +155 582 l + +ce} _d +/O{512 0 41 8 471 776 sc +93 689 m +128 747 183 776 256 776 c +329 776 383 747 418 689 c +453 632 471 533 471 392 c +471 251 453 152 418 94 c +383 37 329 8 256 8 c +183 8 128 37 93 94 c +58 152 41 251 41 392 c +41 533 58 632 93 689 c + +183 108 m +202 91 226 82 256 82 c +286 82 310 91 328 108 c +347 125 361 157 372 203 c +383 250 389 313 389 392 c +389 471 383 534 372 580 c +361 627 347 659 328 676 c +310 693 286 702 256 702 c +226 702 202 693 183 676 c +165 659 150 627 139 580 c +128 534 123 471 123 392 c +123 313 128 250 139 203 c +150 157 165 125 183 108 c + +ce} _d +/P{512 0 77 18 466 776 sc +384 551 m +384 605 372 644 347 668 c +322 693 284 705 232 705 c +204 705 180 702 161 696 c +161 397 l +181 394 205 392 232 392 c +285 392 323 404 347 428 c +372 453 384 494 384 551 c + +466 551 m +466 469 448 410 412 374 c +376 339 320 321 243 321 c +219 321 192 323 161 326 c +161 18 l +77 18 l +77 761 l +130 771 185 776 241 776 c +318 776 375 758 411 722 c +448 687 466 630 466 551 c + +ce} _d +/R{512 0 72 18 481 776 sc +379 571 m +379 660 328 705 227 705 c +199 705 175 702 156 696 c +156 418 l +217 418 l +276 418 318 429 342 452 c +367 475 379 514 379 571 c + +156 346 m +156 18 l +72 18 l +72 761 l +125 771 180 776 236 776 c +312 776 368 759 405 725 c +442 692 461 640 461 571 c +461 474 424 408 349 374 c +349 372 l +370 361 393 317 417 238 c +481 18 l +393 18 l +333 240 l +321 283 307 312 290 325 c +274 339 246 346 207 346 c +156 346 l + +ce} _d +/S{512 0 72 8 451 776 sc +266 702 m +234 702 208 692 187 671 c +166 650 156 624 156 592 c +156 558 163 530 178 507 c +193 485 217 466 251 451 c +327 417 379 382 408 345 c +437 309 451 262 451 203 c +451 138 433 90 398 57 c +363 24 312 8 246 8 c +184 8 128 27 77 65 c +77 162 l +132 109 190 82 251 82 c +328 82 367 122 367 203 c +367 240 358 271 340 296 c +322 321 292 342 251 361 c +187 390 141 422 113 459 c +86 496 72 540 72 592 c +72 647 89 691 124 725 c +159 759 204 776 261 776 c +297 776 327 773 350 768 c +373 763 400 752 430 735 c +430 643 l +377 682 323 702 266 702 c + +ce} _d +/T{512 0 56 18 456 766 sc +214 18 m +214 694 l +56 694 l +56 766 l +456 766 l +456 694 l +298 694 l +298 18 l +214 18 l + +ce} _d +/U{512 0 61 8 451 766 sc +402 58 m +369 25 321 8 256 8 c +191 8 143 25 110 58 c +77 91 61 143 61 213 c +61 766 l +147 766 l +147 233 l +147 178 156 139 174 116 c +193 93 221 82 258 82 c +295 82 323 93 341 116 c +360 139 369 178 369 233 c +369 766 l +451 766 l +451 213 l +451 143 435 91 402 58 c + +ce} _d +/V{512 0 31 18 481 766 sc +259 90 m +397 766 l +481 766 l +307 18 l +205 18 l +31 766 l +119 766 l +257 90 l +259 90 l + +ce} _d +/X{512 0 51 18 461 766 sc +257 469 m +259 469 l +374 766 l +459 766 l +307 402 l +461 18 l +369 18 l +255 331 l +253 331 l +138 18 l +51 18 l +205 402 l +53 766 l +143 766 l +257 469 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 +0 0 translate +0 0 504 72 rectclip +gsave +0 0 m +504 0 l +504 72 l +0 72 l +cl +1 setgray +fill +grestore +gsave +0 36 m +504 36 l +504 72 l +0 72 l +0 36 l +cl +grestore +0 setgray +/WenQuanYiZenHei-0 16.000 selectfont +gsave + +55.4375 49.2031 translate +0 rotate +0 0 m /W glyphshow +13.1094 0 m /e glyphshow +21.7344 0 m /n glyphshow +30.3594 0 m /Q glyphshow +40.9062 0 m /u glyphshow +49.5312 0 m /a glyphshow +58.1562 0 m /n glyphshow +66.7812 0 m /Y glyphshow +75.7344 0 m /i glyphshow +79.5625 0 m /space glyphshow +84.3594 0 m /Z glyphshow +92.9844 0 m /e glyphshow +101.609 0 m /n glyphshow +110.234 0 m /space glyphshow +115.031 0 m /H glyphshow +125.578 0 m /e glyphshow +134.203 0 m /i glyphshow +138.031 0 m /colon glyphshow +142.828 0 m /space glyphshow +147.625 0 m /A glyphshow +156.578 0 m /B glyphshow +166.484 0 m /C glyphshow +176.391 0 m /D glyphshow +186.938 0 m /E glyphshow +195.891 0 m /F glyphshow +203.562 0 m /G glyphshow +214.109 0 m /H glyphshow +224.656 0 m /I glyphshow +228.812 0 m /J glyphshow +235.203 0 m /K glyphshow +245.109 0 m /L glyphshow +253.109 0 m /M glyphshow +266.219 0 m /N glyphshow +276.766 0 m /O glyphshow +287.312 0 m /P glyphshow +296.266 0 m /Q glyphshow +306.812 0 m /R glyphshow +316.719 0 m /S glyphshow +326.625 0 m /T glyphshow +334.625 0 m /U glyphshow +344.859 0 m /V glyphshow +353.812 0 m /W glyphshow +366.922 0 m /X glyphshow +375.547 0 m /Y glyphshow +384.5 0 m /Z glyphshow +grestore +gsave +0 0 m +504 0 l +504 36 l +0 36 l +0 0 l +cl +grestore +/WenQuanYiZenHeiMono-0 16.000 selectfont +gsave + +52 13.2031 translate +0 rotate +0 0 m /W glyphshow +8 0 m /e glyphshow +16 0 m /n glyphshow +24 0 m /Q glyphshow +32 0 m /u glyphshow +40 0 m /a glyphshow +48 0 m /n glyphshow +56 0 m /Y glyphshow +64 0 m /i glyphshow +72 0 m /space glyphshow +80 0 m /Z glyphshow +88 0 m /e glyphshow +96 0 m /n glyphshow +104 0 m /space glyphshow +112 0 m /H glyphshow +120 0 m /e glyphshow +128 0 m /i glyphshow +136 0 m /space glyphshow +144 0 m /M glyphshow +152 0 m /o glyphshow +160 0 m /n glyphshow +168 0 m /o glyphshow +176 0 m /colon glyphshow +184 0 m /space glyphshow +192 0 m /A glyphshow +200 0 m /B glyphshow +208 0 m /C glyphshow +216 0 m /D glyphshow +224 0 m /E glyphshow +232 0 m /F glyphshow +240 0 m /G glyphshow +248 0 m /H glyphshow +256 0 m /I glyphshow +264 0 m /J glyphshow +272 0 m /K glyphshow +280 0 m /L glyphshow +288 0 m /M glyphshow +296 0 m /N glyphshow +304 0 m /O glyphshow +312 0 m /P glyphshow +320 0 m /Q glyphshow +328 0 m /R glyphshow +336 0 m /S glyphshow +344 0 m /T glyphshow +352 0 m /U glyphshow +360 0 m /V glyphshow +368 0 m /W glyphshow +376 0 m /X glyphshow +384 0 m /Y glyphshow +392 0 m /Z 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 index dbb0d5f60f3c..8dea73a697d6 100644 --- 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 @@ -1,1124 +1,798 @@ - - + + + + + + 2026-04-02T23:47:58.161774 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+gef9968a6c, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - + - + - - - - - - - - - + - - - - - + + + + + - - - - - - + - + - - - + + - - - +" transform="scale(0.015625)"/> + + - - - - - - + - + - - - - - - + + + + + + - - - - - - + - + - - - - - - + + + + + + - - - - - - + - + - - - + + - - - - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + - - + - - - + - - - - - - - - - - - - - - - - +M 947 1747 +Q 947 1113 1208 752 +Q 1469 391 1925 391 +Q 2381 391 2643 752 +Q 2906 1113 2906 1747 +Q 2906 2381 2643 2742 +Q 2381 3103 1925 3103 +Q 1469 3103 1208 2742 +Q 947 2381 947 1747 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + - - - - - - - - - + - + - + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - - - - - - - - - - - - - - - - - - - - + + - - - - - - - + + - + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - - - - - - - - - - - - - - - - - - - - + + - + - - + + - - + - - - - + - + - - - - - - - - - - - - - +M 2181 722 +Q 2541 722 2730 984 +Q 2919 1247 2919 1747 +Q 2919 2247 2730 2509 +Q 2541 2772 2181 2772 +Q 1825 2772 1636 2509 +Q 1447 2247 1447 1747 +Q 1447 1247 1636 984 +Q 1825 722 2181 722 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + - - + + - + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + - - + + 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..2922e6bd59f4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_svg/bold_font_output_with_none_fonttype.svg @@ -0,0 +1,413 @@ + + + + + + + + 2026-03-13T23:13:43.457201 + image/svg+xml + + + Matplotlib v3.11.0.dev2075+g5a13dc378e, 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..07d400c94e03 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_svg/multi_font_aspath.svg @@ -0,0 +1,16558 @@ + + + + + + + + 2026-04-03T00:27:07.918200 + image/svg+xml + + + Matplotlib v3.11.0.dev2222+g4230aa142, 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..f2671f5fe247 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_svg/multi_font_astext.svg @@ -0,0 +1,52 @@ + + + + + + + + 2026-04-03T00:27:08.459316 + image/svg+xml + + + Matplotlib v3.11.0.dev2222+g4230aa142, 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..1411966bfdf2 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..46facee23546 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..dbaf03567fc7 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..26c9dd7576b2 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..3349e460c76e 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..7154475f7320 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 @@ -1,235 +1,162 @@ - - + + + + + + 2026-04-02T23:53:17.806175 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+gef9968a6c, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - - - - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - - - - + - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - - - - - - - - - - - - - + - + + + + + + + + + + + + + + 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 07a842d7ad79..82c5dba74f90 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 e7b76e784002..dd685652c72d 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 ca4e08f6a766..a5c7e7582ebe 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,1196 +1,857 @@ - - + + + + + + 2026-04-02T23:53:17.217505 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+gef9968a6c, 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)"/> + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - - - - + + - - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + - - - - - - - + + - + - + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + - + + + + + + + + + + + + + + + + - - + + - - + + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + - +" style="fill: #ffffff; opacity: 0.8; stroke: #cccccc; 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..51317ece2560 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 5b3fb87829a4..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 87596b272f8e..fcc73e5cc1b4 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 47ae3594a12d..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__add_positions.svg +++ /dev/null @@ -1,831 +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 b4c12229a2e3..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 3a7759107c27..c60c2b92b74a 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 6f00d22b4d8d..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__append_positions.svg +++ /dev/null @@ -1,834 +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 9c4a608205ff..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 21b004c7420a..765e44e5cc34 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 b5c89be1e12c..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__default.svg +++ /dev/null @@ -1,710 +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 52aed02f1c8f..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 d4b4bed31cb1..283fc62315df 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 ceab21bbc62d..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__extend_positions.svg +++ /dev/null @@ -1,820 +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 9fd195b6f5fa..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 e80a6b7d3262..2c5adf013a9c 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 d4f3ff5a1064..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_color.svg +++ /dev/null @@ -1,671 +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 be1d76c08b8a..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 fa05103fa61a..e3d61cc50058 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 d08eb17dda3e..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linelength.svg +++ /dev/null @@ -1,782 +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 90dee7c4d0cb..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 9c74479efcbc..821b14d61f95 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 a249a36e281a..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_lineoffset.svg +++ /dev/null @@ -1,741 +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 632db77f9236..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 b9f699ab29dd..b01e28fadddb 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 52845340b254..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linestyle.svg +++ /dev/null @@ -1,675 +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 057c7b3b9f8a..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 03683c070377..55ce408ee2fe 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 97f8cf3f1f5e..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linewidth.svg +++ /dev/null @@ -1,716 +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 f2d29a334ae9..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 be5cc133dc72..8445a0065101 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 4f1d2bffde2b..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_orientation.svg +++ /dev/null @@ -1,707 +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 14d0940c1d50..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 b0cf2392004b..e026997d029d 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 fb274e8852a2..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_positions.svg +++ /dev/null @@ -1,781 +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 41fd0b59902b..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 24b54b99e984..bd086fc047b0 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 7b10351eb44a..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation.svg +++ /dev/null @@ -1,744 +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 24b14fb4620b..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 3db03db40705..18788420ed17 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 50cdbb73fb0b..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation__2x.svg +++ /dev/null @@ -1,764 +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..491085095296 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 49e4bda28ab9..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/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..d9b7e396a580 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..e82603f0d296 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..e71e390536b1 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..ee5c887ae77f 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.pdf b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_closed_patch.pdf deleted file mode 100644 index 81271ec29c81..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_closed_patch.pdf and /dev/null 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 index 68e32ff001f0..b4abeda53746 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_closed_patch.png 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_closed_patch.svg b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_closed_patch.svg deleted file mode 100644 index cc3a43b71f04..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_closed_patch.svg +++ /dev/null @@ -1,660 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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..411a2511dc54 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..8d3ab44f3e7a 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..adfd661fb6e5 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..585548061a1d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_colorbar/nonorm_colorbars.svg @@ -0,0 +1,149 @@ + + + + + + + + 2026-03-12T19:44:58.015301 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..99b97338a2e8 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 9409f83bf7c7..f8065ce646c6 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..b014a8f1eaa5 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_colors/test_norm_abc.png b/lib/matplotlib/tests/baseline_images/test_colors/test_norm_abc.png new file mode 100644 index 000000000000..c2169461d075 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colors/test_norm_abc.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..b4565e4c5c18 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..1b801d37ac98 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..190ba3758ffd 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..5bcd4248fe2e 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..e638623b560b 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..e7dea38efcc9 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..716c729f48a4 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..189474e52df0 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..231615afb00e 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_constrainedlayout/test_compressed_suptitle_colorbar.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_compressed_suptitle_colorbar.png new file mode 100644 index 000000000000..df4ecaf939c7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_compressed_suptitle_colorbar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_compressed_supylabel_colorbar.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_compressed_supylabel_colorbar.png new file mode 100644 index 000000000000..cd6e38e62f00 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_compressed_supylabel_colorbar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_submerged_with_colorbar.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_submerged_with_colorbar.png new file mode 100644 index 000000000000..f53c2b8035a9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_submerged_with_colorbar.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 index 93780be92fc1..6adce0339853 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_contour/contour_corner_mask_False.png 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_datetime_axis.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_datetime_axis.png index 70d76ce3e3af..7cdc21e820b9 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..5a576317f6f3 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..c1289945297d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_contour/contour_log_locator.svg @@ -0,0 +1,3351 @@ + + + + + + + + 2026-03-12T19:44:40.936001 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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 418977d7ca9b..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 6404ae457352..93765a09f0ab 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 f5e37a27b097..584d8c8fac72 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 07069546f640..929487f29122 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,814 +1,456 @@ - - + + + + + + 2026-03-13T23:13:18.517824 + image/svg+xml + + + Matplotlib v3.11.0.dev2075+g5a13dc378e, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - + - - - - - - - - - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - - - - + - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + - - + + 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..da86441fdd91 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 d03c57fb7f8f..5cf16ce9899d 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 50d99cebb947..ea96ff664f32 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 90a08f29bc35..7792ab44c149 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 65091c524fb1..ec5accd3239c 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 8ace4d7d12fc..ef6ae34292c0 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 2958b74cc542..3019e344541a 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 15d6ee409215..241a745df79d 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 4013d973d35a..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 328a10dd3f34..119cd45b6316 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..42fd1f453d69 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..c4d1b5c412c1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_figure/figure_align_labels.svg @@ -0,0 +1,1649 @@ + + + + + + + + 2026-04-02T23:50:14.646768 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+gef9968a6c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..9d2003008d19 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..641f5ab24c69 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..557337ae37b7 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 d7478fcdd75b..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 463680c84b38..811c7c23219e 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 e3ff927a06bc..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_figure/figure_suptitle.svg +++ /dev/null @@ -1,556 +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 d7aaf708e8d5..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 bd3bc532bedb..411e24fc2123 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 1942a3f5048c..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_figure/figure_today.svg +++ /dev/null @@ -1,729 +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..61078e30e64f 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..f15229e7684c 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..f4c3c9152e54 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..bd1423219b57 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..db85f9bf0923 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..2cd3fc88180f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.svg @@ -0,0 +1,806 @@ + + + + + + + + 2026-03-12T19:47:32.918677 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/affine_fill_to_edges.png b/lib/matplotlib/tests/baseline_images/test_image/affine_fill_to_edges.png new file mode 100644 index 000000000000..88858eda5d94 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/affine_fill_to_edges.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/alignment_half_display_pixels.png b/lib/matplotlib/tests/baseline_images/test_image/alignment_half_display_pixels.png new file mode 100644 index 000000000000..e822ced620f2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/alignment_half_display_pixels.png differ 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 bd9c37291a0e..4fa9dc748b02 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 602168b49f50..0d2b7b459ecb 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..268c9d14f605 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.svg @@ -0,0 +1,164 @@ + + + + + + + + 2026-01-30T01:57:12.969851 + image/svg+xml + + + Matplotlib v3.11.0.dev1729+g1f7cad29d, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..e7c6ca7b1c35 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..daa1dc248116 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..f4d80f2a5ec4 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..301a55c03ad5 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..47b489e391bb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/image_alpha.svg @@ -0,0 +1,609 @@ + + + + + + + + 2026-01-30T01:57:05.781655 + image/svg+xml + + + Matplotlib v3.11.0.dev1729+g1f7cad29d, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_bounds_handling.png b/lib/matplotlib/tests/baseline_images/test_image/image_bounds_handling.png new file mode 100644 index 000000000000..3a817f331c42 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/image_bounds_handling.png differ 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 577157285e0f..a30b6ffe64e8 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 69d2a9acbcd7..79db3d01c382 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 296e45191a99..f6f8d2780a22 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/image_clip.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/image_clip.svg @@ -1,544 +1,501 @@ - - + + + + + + 2026-03-12T19:45:17.564380 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - - - + + - - + - - - + + + + + + + + + + - + - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + - - - - + + + + + + + + + + + + + + - - - - - + + + + + + + + + - - - - - - + + + - - - - - - - - + + + + + + + - - - - - - - - + + + + - - - - - - - - - + + + + + + + - - + - + - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + - - - - - + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + - - - - - - + + + - - - - - - - - + + + + + + + - - - - - - - + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + - - + 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 c3eabba16def..8266576312a4 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 4c5b60e34725..1581dcc06438 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 e633c2ea92d3..73b812d8e2d7 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.svg @@ -1,449 +1,388 @@ - - + + + + + + 2026-03-12T19:45:18.012205 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - + + - - - - - - - - - + - + - - - - - + + + + + - - - - - - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - - - - - - + - + - - - - - + + + + + - - - - - - + - + - - - - - + + + + + - - - - - - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - - - - - - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - - - - - - - - - + - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + + + + + + + + + + + + + - - + + 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..b8cd42f9dde4 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..6c772a880861 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..de9e2ca0d936 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,146 @@ - - + + + + + + 2026-02-03T19:56:08.323770 + image/svg+xml + + + Matplotlib v3.11.0.dev1757+g00c32c31d, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #008000"/> - - + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -120,93 +149,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..873ee0ef14ce 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..d02f898cbe52 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..f0fdcd26b455 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 @@ -1,272 +1,190 @@ - - + + + + + + 2026-01-30T01:57:11.186332 + image/svg+xml + + + Matplotlib v3.11.0.dev1729+g1f7cad29d, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" 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 d3d258d74348..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 a1895fd3d603..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 33c144b5140f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_image/image_interps.svg +++ /dev/null @@ -1,1174 +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..2b13a801e1c8 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..8de0a4e34204 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..8d3005b781db 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..c7683cc6f939 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..292d3b1c0c2a 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..977667d6abc2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.svg @@ -0,0 +1,196 @@ + + + + + + + + 2026-02-08T04:35:48.823370 + image/svg+xml + + + Matplotlib v3.11.0.dev1781+g34b8e3347, 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..804cbc50d5f3 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..129cbb20816b 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..2f1e9fca18bb 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,320 +1,322 @@ - - + + + + + + 2026-04-03T00:07:29.936854 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+gef9968a6c.d20260403, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - + + - + - + + + - - - - + - + - + + + - + - + - + + + + + + + + - + - + - + + + - + - + - + + + - + - - - + - - - - + + + - - - - + - + - - - - - - + - - - - - - - + + - + - + - + - + - + - +" style="fill: #ffffff"/> - - + + + + + + + + + + + + + + + + - + + + - + - + - + + + + + - + - + - + + + - + - + - + + + - + - + - + + + - + - - - + - - - - - - - - - - - - - - - - - - + - - - - - - - + + - + - + - + - + - + - - + + - - + + 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..3ff7ac577202 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..453ea0ab2342 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..e9bde5b99554 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/log_scale_image.svg @@ -0,0 +1,393 @@ + + + + + + + + 2025-07-10T19:29:53.473547 + image/svg+xml + + + Matplotlib v3.11.0.dev1075+g945334b731, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..934e42483498 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..95b1fb40fea3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/mask_image.svg @@ -0,0 +1,376 @@ + + + + + + + + 2026-01-30T01:57:16.776745 + image/svg+xml + + + Matplotlib v3.11.0.dev1729+g1f7cad29d, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..7cdff0a5487c 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/nn_pixel_alignment.png b/lib/matplotlib/tests/baseline_images/test_image/nn_pixel_alignment.png new file mode 100644 index 000000000000..3821a8a517fa Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/nn_pixel_alignment.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..2ee3019d6294 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..58d1ce37c42f 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..25653c4dd277 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..739de6ee17c7 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..7e8f573a1037 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg @@ -1,80 +1,87 @@ - - + + + + + + 2026-01-31T05:22:32.107077 + image/svg+xml + + + Matplotlib v3.11.0.dev1730+g53f57dd80, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - + + - +" style="fill: #ffffff"/> - + - - - - +" style="fill: #ffffff"/> + + + - - + + - - + + 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..e33c7effbbb8 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/rgba_clean_edges.png b/lib/matplotlib/tests/baseline_images/test_image/rgba_clean_edges.png new file mode 100644 index 000000000000..467a757f933f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/rgba_clean_edges.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..1aa443ee55b6 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..430aaa11d8cd 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 index dbec3749eed7..f803b7a9d4de 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/zoom_and_clip_upper_origin.png 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 7930f6d68249..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 36d535ac79f3..a2041b7dc8ca 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 0310db349d41..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/fancy.svg +++ /dev/null @@ -1,779 +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 ab51c81afeb1..442a2accd056 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 295cf3aee7df..5343917be870 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 17deb757761e..88e2f0568fd7 100644 --- a/lib/matplotlib/tests/baseline_images/test_legend/framealpha.svg +++ b/lib/matplotlib/tests/baseline_images/test_legend/framealpha.svg @@ -1,498 +1,441 @@ - - + + + + + + 2026-04-03T00:28:44.349245 + image/svg+xml + + + Matplotlib v3.11.0.dev2222+g4230aa142, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - - - - - - - - - + - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - - - - + - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + + + + + + + + + + + + + + + + - +" style="fill: #ffffff; opacity: 0.5; stroke: #cccccc; stroke-linejoin: miter"/> - - + + - - - - + + - + - + - + - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + - - + + 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..e360d5aca6a5 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..2d5cfc8f1883 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..29983db3d473 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_legend/hatching.svg @@ -0,0 +1,1070 @@ + + + + + + + + 2026-03-12T19:45:43.532119 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 a43ddcf2731e..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 ba2a6e2ef028..baa71b173451 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 6a029cf5b3a5..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto1.svg +++ /dev/null @@ -1,575 +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 7867ce83d9bc..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 0c2c53885ee2..6a6af293c5f7 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 f6efe064b4b9..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto2.svg +++ /dev/null @@ -1,2198 +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 d0386304d9e6..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 c7a8e3585493..c71515453efa 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 74d6592eead9..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.svg +++ /dev/null @@ -1,610 +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 dfd7e28f4435..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 292a88db0208..86e0da56012b 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 b47c5dff14c3..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/legend_expand.svg +++ /dev/null @@ -1,1159 +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 34339d2aa2f8..e2d3be4089c0 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..d9429c1c0290 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 113de4b5ae30..ee4989c512c4 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 a16341c99039..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..67ddb90da287 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 36b662a2a55f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.svg +++ /dev/null @@ -1,614 +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..d94b074b33c1 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..f27b0d6546f0 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 index 3f2fd6a8eff0..31723aa8dea9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/rcparam_alpha.png 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 index 1037ff371a0b..314d665518d1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/rgba_alpha.png 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 c7fae8bd6dde..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 a23ded35a626..58f146f5019e 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 d39bf92fbded..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc1.svg +++ /dev/null @@ -1,516 +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 321d75f1ae41..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 87799d7ad837..5addd799b4b6 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 140f201803ce..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc3.svg +++ /dev/null @@ -1,555 +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..010bebee5157 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..5d13d34f15e6 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..a04f90f171e4 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..248056f322f7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_lines/scaled_lines.svg @@ -0,0 +1,2007 @@ + + + + + + + + 2026-03-12T19:45:49.209875 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..e7fade353e60 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 e3f8aad8668d..91150d2c2922 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 22a0196686bd..e46bb62c3f02 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 d84ef474305f..922a2fc5f9e0 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 1d21f73e60d5..7c3ee7d3d6bd 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 739b8310373c..ed831bb8cf5b 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 cca48c5c515d..20048247a899 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 4550a99b2bc4..5769c591714a 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 51aa52e990cc..5ff42c34392e 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 a9403888fda7..e959a733ab0b 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 cc0c60787ee9..77b8412948b4 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 02244768273b..bb74cd5f165b 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 99c51683c527..cae4e006110f 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 e9df0cd4ac60..a701f08389de 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 51a5b874e086..e3faabead9b6 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 721d4e2c8419..2196f71f8eac 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 48a229b5dfe0..c5ca67dd03be 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 403cf6664ea8..5e2ff07c0541 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 3652654b3c82..11f662f9aae7 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 96ee31d81190..7ee8d38002b7 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 3f0513986307..8045f17cd715 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 797704836125..2c6429267d13 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 b2e6d2221a58..66298251d8b5 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 5548ff8c7a8d..c57534104b4b 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 a0b1d6191831..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 75360ea2e688..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 eed11d8ef86a..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 324577a22bcd..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 b93a9e955600..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 fb0de2d3ac87..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 b9d50284678d..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 6f54263613e0..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 a59b0081b837..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 b56de1e4c108..73cf51d1ea20 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 eee033aaf73b..22edfa0ed1ba 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 281880dcf979..4dfd1beedf3e 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 39fe61d4191c..15e0af6e9bad 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 273770bc08b8..dab9f5edd1d0 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 f8126567e91f..cb2c1d4ce441 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 cd6de3c09052..810467897d06 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 1e103ff391cd..c4c809793c31 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 edbf803f4842..cadc0a85baf9 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 c13628c8aba5..45af7b72a2ea 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 729d3b8ae0f9..d862e5563b35 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 54840062e1be..b7774d9e7788 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 87526333cdbd..dcd6d81702c2 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 7a89af4e1cae..38a2dc7ce722 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 a2898a570209..7f2b33b5c867 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 1be8f13ce6a4..875a83baed23 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 63a17add745f..9d2ee6e573b0 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 0e4370e44715..ed7a48f0ce28 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 4d5497c5be86..5d37ed6eea3b 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 86e39d655a8e..b35664168529 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 a695f999e723..25e662ea315f 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 b318e1d55e93..64213b476090 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 88fa83b11147..240e1c5d380b 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 415fc0fa44a4..6683bd061e75 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 80206e71cb53..da87d3f1534b 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 d9da9dfc33f5..f933883b212d 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 f55a005b34c3..282d1f174440 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 3c577d94dd32..076e784e13a5 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..ffd75bee281d 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..495ecd6e1c35 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..db904d1e8136 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..52ba874bc02d 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..41ae5fbe3cce 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..24c7c257e396 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..41d5413e50b7 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..b4140bbcab9e 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..cef5ef0dfa44 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..ac3d0b6f9d82 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..1a6b2339e425 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..8a1f18efcf86 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..ec7a9ec3ea83 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..c7eb8cefd1b0 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..712a93516944 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..a7fa31fb7c39 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..9de63f7e1d5d 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..975185df0ae6 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..33d80705362f 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..befb19e8cf6d 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..45cc5c10dc65 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..bb7d88241b60 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..ee24c715b6b5 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..5e63206c92bd 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..037d11f4b953 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..1386dc1b7fc2 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..26bf5e0506aa 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..74be6d6e1aa4 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..73cf51d1ea20 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..22edfa0ed1ba 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..4dfd1beedf3e 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..99c28d9d4334 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..dab9f5edd1d0 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..cb2c1d4ce441 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..810467897d06 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..c4c809793c31 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..cadc0a85baf9 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..45af7b72a2ea 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..d862e5563b35 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..b7774d9e7788 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..fe938b8248c6 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..38a2dc7ce722 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..7f2b33b5c867 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..875a83baed23 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..9d2ee6e573b0 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..ed7a48f0ce28 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..5d37ed6eea3b 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..f4ca56276119 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..53ff19aa151c 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..4bcfb575546b 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..816dad31bf03 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..a39a32a3a80d 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..f529ee07d9f7 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..bb4e5be9b78c 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..efc94fbd32d4 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..ad2b436ba0dc 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..156659640530 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..13291076962f 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..9a0e2d05f308 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..6e37554e6eb6 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..81697ec50d92 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..ff9796a877e2 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..7679cf235a90 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..3f2bf30948ac 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..2284c9f5536e 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..3c2729bdec62 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..aeeffbbaf8fe 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..db954c33d046 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..2cb2648033d1 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..fccf55e4011c 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..29c8af2ca764 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..5d6814472853 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..5f4047313d88 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..cd51d1de85ba 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..80e5d4493802 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..685a396a8b87 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..de289fb56d2a 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..a22862dcf24c 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..25d0bfe1dd97 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..f42a36885574 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..750f5275e164 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..1386dc1b7fc2 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..26bf5e0506aa 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..74be6d6e1aa4 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..73cf51d1ea20 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..22edfa0ed1ba 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..4dfd1beedf3e 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..15e0af6e9bad 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..dab9f5edd1d0 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..cb2c1d4ce441 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..810467897d06 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..c4c809793c31 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..cadc0a85baf9 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..45af7b72a2ea 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..d862e5563b35 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..b7774d9e7788 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..fe938b8248c6 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..38a2dc7ce722 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..7f2b33b5c867 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..875a83baed23 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..9d2ee6e573b0 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..ed7a48f0ce28 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..5d37ed6eea3b 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..f4ca56276119 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..53ff19aa151c 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..4bcfb575546b 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..816dad31bf03 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..a39a32a3a80d 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..f529ee07d9f7 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..bb4e5be9b78c 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..efc94fbd32d4 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..ad2b436ba0dc 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..a32188889818 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..8bc5e03d80b8 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..6b2cdd1d9131 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..9f30c6bd1ccf 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..88cb815aa68f 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 42874c7b1fb8..201318c06a4f 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 130529175ff6..373db385ccce 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 ede3d2a5a8fe..2e1fbb39e6c0 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 ab73c030ccc6..acae2cc52a2c 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 e32ecd0e488a..e38923675661 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 f26a39e6e6c1..0706652d9ef6 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 eefb020b9725..2ed7e2830311 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 823a7a00168e..476134298d81 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 49fef9e05caa..b20fd61d73eb 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 d46bc06477b8..6b7eb4d37cd9 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 749520cb98a1..976f94dc1344 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 92c96f37717d..8982cb2a28b3 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 5f6b6a0588af..cbe666d12f58 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 c6259abbad1d..4a77cfcfff32 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 aab07321f8f9..a12e86ac4566 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 c16668aa71f1..dff487fc2452 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 4e590017f35b..60250abeed83 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 bb2945a738f7..d1d46b7c5159 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 a6de87719ce2..7e1fd4045927 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 6d376a469929..ce876adc1684 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 0c3816d0b4ec..d5d0d211c4dc 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 4a756814afd6..759030051a90 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 8c4100e448ff..07e71421e4db 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 a0b1d6191831..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 75360ea2e688..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 eed11d8ef86a..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 324577a22bcd..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 b93a9e955600..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 fb0de2d3ac87..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 b9d50284678d..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 6f54263613e0..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 a59b0081b837..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 b56de1e4c108..73cf51d1ea20 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 eee033aaf73b..22edfa0ed1ba 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 281880dcf979..4dfd1beedf3e 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 39fe61d4191c..15e0af6e9bad 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 273770bc08b8..dab9f5edd1d0 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 f8126567e91f..cb2c1d4ce441 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 cd6de3c09052..810467897d06 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 1e103ff391cd..c4c809793c31 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 edbf803f4842..cadc0a85baf9 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 c13628c8aba5..45af7b72a2ea 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 729d3b8ae0f9..d862e5563b35 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 54840062e1be..b7774d9e7788 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 90fc7d785c5f..fe938b8248c6 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 7a89af4e1cae..38a2dc7ce722 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 a2898a570209..7f2b33b5c867 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 1be8f13ce6a4..875a83baed23 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 63a17add745f..9d2ee6e573b0 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 0e4370e44715..ed7a48f0ce28 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 4d5497c5be86..5d37ed6eea3b 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 fab0b18f5c16..6f78ea9de0ed 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 a9fcef2631bb..9a7f09e696ab 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 377cfc2a4e9e..90a19ded6da5 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 b3afae56f1ac..dd12803729ce 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 1f4981d2c7b2..d096098943e6 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 d1b051c107dd..bb698a10ead9 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 1428e8ae5b71..186e0e03e39b 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 a0f9dba5c5d3..e916d96d336a 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 e98f19f58e2c..c7c750dfcb96 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..ffd75bee281d 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..495ecd6e1c35 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..db904d1e8136 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..52ba874bc02d 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..41ae5fbe3cce 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 f8ddd1da3ed9..8ca8fde71712 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 0ec803064fc9..3e0ce6302afb 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 c6d504d82cd3..6accb07688d0 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 bdd23cc0e018..cb6984428bef 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 1d8851d50224..df0c4054d240 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 24b23378acfa..15c4f7a6362b 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 2eb1df03f66f..a69659364e74 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 e1b4ce105692..1ebe25e1680e 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 69ec8ed916a0..12de76dff0cf 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 e42fa46600e7..6e3b1c454e72 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 988bb9d7f303..2763fc7e6966 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 231f1a2a32d7..de800aa6d23a 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 a0cdbcb964a1..dc9eb4cc225e 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 ccceaea3ceea..76dfc863390e 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 4ede1596f4f9..1004091a5c42 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 6df1e731ec1f..a4800741d806 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 6263b84873fb..3f6893bb8eb1 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 84b0ab14907e..8e63f34fff59 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 a82ac878eda9..cb52336ff2ba 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 02cea4a1ba5e..5678a91a9806 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 0c3816d0b4ec..d5d0d211c4dc 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 4a756814afd6..759030051a90 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 8c4100e448ff..07e71421e4db 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 a0b1d6191831..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 75360ea2e688..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 eed11d8ef86a..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 324577a22bcd..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 b93a9e955600..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 fb0de2d3ac87..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 b9d50284678d..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 6f54263613e0..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 a59b0081b837..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 b56de1e4c108..73cf51d1ea20 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 eee033aaf73b..22edfa0ed1ba 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 281880dcf979..4dfd1beedf3e 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 a4103c94eace..99c28d9d4334 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 273770bc08b8..dab9f5edd1d0 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 f8126567e91f..cb2c1d4ce441 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 cd6de3c09052..810467897d06 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 1e103ff391cd..c4c809793c31 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 edbf803f4842..cadc0a85baf9 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 c13628c8aba5..45af7b72a2ea 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 729d3b8ae0f9..d862e5563b35 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 54840062e1be..b7774d9e7788 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 90fc7d785c5f..fe938b8248c6 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 7a89af4e1cae..38a2dc7ce722 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 a2898a570209..7f2b33b5c867 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 1be8f13ce6a4..875a83baed23 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 63a17add745f..9d2ee6e573b0 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 0447a17dc31e..ed7a48f0ce28 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 4d5497c5be86..5d37ed6eea3b 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 fab0b18f5c16..6f78ea9de0ed 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 a9fcef2631bb..9a7f09e696ab 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 377cfc2a4e9e..90a19ded6da5 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 b3afae56f1ac..dd12803729ce 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 1f4981d2c7b2..d096098943e6 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 d1b051c107dd..bb698a10ead9 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 1428e8ae5b71..186e0e03e39b 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 a0f9dba5c5d3..e916d96d336a 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 e98f19f58e2c..c7c750dfcb96 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..ffd75bee281d 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..5eb13fe9a26e 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..992ba3224b23 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..852e79665974 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..f615a48b3f4c 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..518d9b9dc069 --- /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_cm_01.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_01.svg new file mode 100644 index 000000000000..813c69f84e05 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_01.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + ( + ) + M + = + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ² + ¡ + ± + ² + ¢ + M + B + B + ³ + . + / + ´ + M + I + M + B + U + I + N + G + ³ + . + / + ´ + µ + Á +  + + M + I + B + U + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_02.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_02.svg new file mode 100644 index 000000000000..06f9a44349c3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_02.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + [ + ] + M + = + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ² + £ + ± + ² + ¤ + M + B + B + h + . + / + i + M + I + M + B + U + I + N + G + h + . + / + i + + Á +  + ¸ + M + I + B + U + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_03.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_03.svg new file mode 100644 index 000000000000..0659dcfd7297 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_03.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + h + i + M + = + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ² + ­ + ® + M + B + B + ± + ² + D + E + M + I + M + B + U + I + N + G + . + / + D + E + . + / + ¿ + Á +  + À + M + I + B + U + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_04.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_04.svg new file mode 100644 index 000000000000..b988f429a576 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_04.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + © + ² + ª + M + = + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + © + ± + ² + ª + M + B + B + n + . + / + o + M + I + M + B + U + I + N + G + n + . + / + o + ½ + Á +  + ¾ + M + I + B + U + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_05.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_05.svg new file mode 100644 index 000000000000..cd30619f2223 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_05.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + ¥ + ² + ¦ + M + = + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ¥ + ± + ² + ¦ + M + B + B + j + . + / + k + M + I + M + B + U + I + N + G + j + . + / + k + ¹ + Á +  + º + M + I + B + U + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_06.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_06.svg new file mode 100644 index 000000000000..1e1423f64b0f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_06.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + § + ² + ¨ + M + = + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + § + ± + ² + ¨ + M + B + B + l + . + / + m + M + I + M + B + U + I + N + G + l + . + / + m + » + Á +  + ¼ + M + I + B + U + + + + + + + + + + + + + + + + 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..1d983187af08 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_00.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_01.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_01.svg new file mode 100644 index 000000000000..092e2336a1ec --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_01.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + ( + / + ? + \ + ? + ) + ? + ? + ? + ? + ? + ? + ? + ? + M + ( + / + \ + ) + M + B + B + ( + / + \ + ) + M + I + M + B + U + I + N + G + ( + / + \ + ) + ( + / + \ + ) + M + B + U + I + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_02.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_02.svg new file mode 100644 index 000000000000..2fd150fe7bb4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_02.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + [ + / + ? + \ + ? + ] + ? + ? + ? + ? + ? + ? + ? + ? + M + [ + / + \ + ] + M + B + B + [ + / + \ + ] + M + I + M + B + U + I + N + G + [ + / + \ + ] + [ + / + \ + ] + M + B + U + I + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_03.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_03.svg new file mode 100644 index 000000000000..7d685d8cb92e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_03.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + / + ? + \ + ? + + ? + ? + ? + ? + ? + ? + ? + ? + M + + / + \ + + M + B + B + + / + \ + + M + I + M + B + U + I + N + G + + / + \ + + + / + \ + + M + B + U + I + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_04.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_04.svg new file mode 100644 index 000000000000..5d70e1c782a9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_04.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + { + / + ? + \ + ? + } + ? + ? + ? + ? + ? + ? + ? + ? + M + { + / + \ + } + M + B + B + { + / + \ + } + M + I + M + B + U + I + N + G + { + / + \ + } + { + / + \ + } + M + B + U + I + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_05.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_05.svg new file mode 100644 index 000000000000..2a2afeaededf --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_05.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + / + ? + \ + ? + + ? + ? + ? + ? + ? + ? + ? + ? + M + + / + \ + + M + B + B + + / + \ + + M + I + M + B + U + I + N + G + + / + \ + + + / + \ + + M + B + U + I + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_06.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_06.svg new file mode 100644 index 000000000000..47173806e844 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_06.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + / + ? + \ + ? + + ? + ? + ? + ? + ? + ? + ? + ? + M + + / + \ + + M + B + B + + / + \ + + M + I + M + B + U + I + N + G + + / + \ + + + / + \ + + M + B + U + I + + + + + + + + + + + + + + + + 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..216ee4deab24 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..d2859e939cff 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..660bca74d9bf 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..23410848950a 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..b5bb3374dce1 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..f967ad200c8b 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..fa0a4583030a 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..a334fc519aa6 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..a25f02964a59 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/mathtext1_dejavusans_09.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_09.png new file mode 100644 index 000000000000..9d96e8eb87b9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_09.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 1dcab930d681..0c1116755704 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 9aba6eedd031..81ed72b857a3 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..1e9d5f2edba3 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 @@ -1,231 +1,249 @@ - - + + + + + + 2026-03-12T19:45:16.353424 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - + + - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + 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 2aa42af97a11..b64cc37e33d8 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 aefda9099d55..5eecc2ab25b3 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..4e6556930cac 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 @@ -1,232 +1,181 @@ - - + + + + + + 2026-03-12T19:45:16.435615 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - + + + + + + + + + + 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 24f07419d9e5..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 354ff9319488..4cc257dcf634 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..f00b12a7d5fa 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 @@ -1,177 +1,193 @@ - - + + + + + + 2026-03-12T19:45:16.486537 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + 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 a48aa96f603a..7fa85a84105a 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 e12507241bd5..3bcab329c091 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..144b2551f408 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 @@ -1,228 +1,242 @@ - - + + + + + + 2026-03-12T18:23:41.028245 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + 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 9817ba4f84b6..84ba64526bcb 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..c9c15f5b7689 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 @@ -1,145 +1,157 @@ - - + + + + + + 2026-03-12T19:45:16.596534 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - + + + + + + + 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 1f8b832e7865..b16268f87d6f 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 0c0591e685be..11a1961f3c30 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..be67bcd7c18f 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 @@ -1,340 +1,357 @@ - - + + + + + + 2026-03-12T19:45:16.647947 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - + + - - - - + - - - - - - - - - - - - - - - - - - - - +M 481 2094 +Q 428 2094 393 2131 +Q 359 2169 359 2222 +Q 359 2269 393 2309 +Q 428 2350 481 2350 +L 4500 2350 +Q 4547 2350 4581 2309 +Q 4616 2269 4616 2222 +Q 4616 2169 4581 2131 +Q 4547 2094 4500 2094 +L 481 2094 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + 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 1641dcb4e344..4b7d845e1a81 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 bea8426a9ab2..5e4016405c6d 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..61ccaeda55c2 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 @@ -1,394 +1,415 @@ - - + + + + + + 2026-03-12T19:45:16.735829 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + 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 0313d072518d..dfc8ea88725a 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 959366a66e61..dcc5cbe22e5c 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..eaeb7a230778 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 @@ -1,216 +1,230 @@ - - + + + + + + 2026-03-12T19:45:16.805663 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + 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 a77d282b05d1..d8c0c298447b 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 074852acd4d3..7da15c0d84aa 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..4b0c61907c41 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 @@ -1,253 +1,264 @@ - - + + + + + + 2026-03-12T19:45:16.871722 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - + - + - + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + 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 dd3bb4a62215..dfcb45bd1efb 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 1e9a5f0d9365..d8964d0d59b4 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..04560dc04e79 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 @@ -1,151 +1,163 @@ - - + + + + + + 2026-03-12T19:45:16.946339 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - + + + + + + + + + + + + + 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 5c45ec65b84e..fd60aafc00d7 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 ccd18b806040..a18a5f2fe2be 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..1ef0f55095ff 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 @@ -1,336 +1,354 @@ - - + + + + + + 2026-03-12T19:45:17.055192 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - + + - + - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + 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 f54f869710fa..2ccf2946a1c5 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 e149f1c46913..033e3840a956 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..b10ae750f9bb 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 @@ -1,347 +1,358 @@ - - + + + + + + 2026-02-06T03:28:08.328699 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - + + - - + - + - - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - 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 7c28a29b2204..058bcb83a3c0 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 18bdef4d61f6..26138357f2f1 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..256df88fb6ea 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 @@ -1,138 +1,150 @@ - - + + + + + + 2026-03-12T19:45:17.201747 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 adf74866733f..c355b8b8e9d1 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..c951ad7ab0ce 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 @@ -1,249 +1,263 @@ - - + + + + + + 2026-03-12T19:45:17.264497 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - + - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + 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 39ba0b17d20a..65675db6c3bd 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 ad67fdf68aa7..ce0b3cd5d12a 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..e702c7c6df60 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 @@ -1,132 +1,143 @@ - - + + + + + + 2026-03-12T19:45:17.357440 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - +" transform="scale(0.015625)"/> + + + + 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 de6ce8ce3576..120b95591954 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 134ac291dfcf..4a007c4e2058 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..ed3cde6e1ac6 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 @@ -1,132 +1,143 @@ - - + + + + + + 2026-03-12T19:45:17.405484 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - +" transform="scale(0.015625)"/> + + + + 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 984ffaa141eb..deac3b99fd6b 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 2918a98cb872..aa775e11a01f 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..3cd0427dbacc 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 @@ -1,187 +1,199 @@ - - + + + + + + 2026-03-12T18:23:41.501759 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 76f134482de4..deac3b99fd6b 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 2918a98cb872..aa775e11a01f 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..097eec3d6ce0 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 @@ -1,187 +1,199 @@ - - + + + + + + 2026-03-12T18:23:41.562003 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 03df83e14681..cea31b038ac7 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 95fdeb32d59c..87838c056199 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..18a9efa2ecf1 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 @@ - - + + + + + + 2026-03-12T18:23:41.595413 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 3c5d8a6ba98f..63efcdd07332 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 1bcf78a080bc..0be7db2fc8e3 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..adf098e9d273 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 @@ -1,427 +1,440 @@ - - + + + + + + 2026-03-01T22:41:05.701701 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - 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 5a02fb5926ed..4aeab88d27ae 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 5399ebe7c612..4dcc7ee0af9b 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..4f3f90f43bb3 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 @@ -1,683 +1,706 @@ - - + + + + + + 2026-03-12T18:23:41.711144 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - - + - + - - - + - - - + - - - - - + - - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 3657cd1d0f61..a9b712c56b14 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 72aba0f52aaa..4ff9d29b1f96 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..617590d8619d 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 @@ -1,748 +1,777 @@ - - + + + + + + 2026-03-12T18:23:41.779182 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 27538aed1839..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 09f0ec4e2b15..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 097b3edcdab6..71d96179d5e5 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 9aeaceb7e2a9..8e61bf598e21 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..ffaf79889a2b 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 @@ -1,321 +1,342 @@ - - + + + + + + 2026-03-12T19:45:17.851781 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - + - - + - + - - - + - - - + - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + + 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 9091f1e3f1a0..6762978138a3 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 5cd8aff02532..dae3dd676803 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..36885d84172b 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 @@ -1,131 +1,145 @@ - - + + + + + + 2026-03-12T18:23:41.890075 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 e7495c6c0599..58dede23681e 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 22938450281a..7d641b275f48 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..bbe35b2282ea 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 @@ -1,176 +1,190 @@ - - + + + + + + 2026-03-12T18:23:41.923588 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - + - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + 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 93611dd9c7ed..f14c5cc3eb75 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 4bac915baff1..bd27c007f3bc 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..d96dda20ac27 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 @@ -1,359 +1,382 @@ - - + + + + + + 2026-03-12T19:45:18.003751 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - + - - - - + - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + 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 e7f1def4968e..20cbe0282b5f 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 389bcba056b6..37445e4e4d37 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..bbdbd5b64a41 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 @@ -1,375 +1,395 @@ - - + + + + + + 2026-03-12T18:23:42.003683 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + 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 8aeff774097e..d1695c1bcef9 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 52a5497f2c08..f3ec7f407bc7 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..a3e6863cbadc 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 @@ -1,369 +1,387 @@ - - + + + + + + 2026-03-12T18:23:42.038971 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - 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 35b24aec143d..8484f89f8094 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 dffb1c0e87fc..7993fa95b151 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..006f98cf5ef2 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 @@ -1,395 +1,411 @@ - - + + + + + + 2026-03-12T19:45:18.187325 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - + - + - - - - + + - - - - - - - - - - - +M 1131 622 +Q 1244 394 1444 245 +Q 1644 97 1881 97 +Q 2103 97 2273 215 +Q 2444 334 2559 534 +Q 2675 734 2729 954 +Q 2784 1175 2784 1381 +Q 2784 1638 2692 1936 +Q 2600 2234 2411 2439 +Q 2222 2644 1953 2644 +Q 1694 2644 1476 2511 +Q 1259 2378 1131 2150 +L 1131 622 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + 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 a709081daeaf..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 304d26588917..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 ab2e575e0de5..7ce3cc5ff35e 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 0117a361ac2c..a2550a03f307 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..50084fc7643e 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 @@ -1,92 +1,307 @@ - - + + + + + + 2026-03-12T18:23:40.726419 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + 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 354e0d77ad41..f31172016a75 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 8c80f8aae144..70b1a7365864 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..074533b31854 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 @@ -1,245 +1,259 @@ - - + + + + + + 2026-03-12T18:23:41.077728 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - - - - - - + + + + + + + + + + + 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 b5f68006d64d..b574a00e1dd8 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 bd33a931add8..e353883189ec 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..93f14cd1a753 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 @@ -1,360 +1,370 @@ - - + + + + + + 2026-03-12T18:23:41.120866 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - + - + - + + - - - - - - - - - - + + + + + + + + + + - 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 1dd52ef45b42..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 7a6a3bcf6f2d..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 02d7a53e374a..9cf6e11d4196 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 f95db4073f6e..55887b85e843 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..bef8ea6ee3c6 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 @@ -1,251 +1,262 @@ - - + + + + + + 2026-03-12T19:45:18.373845 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - + + - - - - - - - - + + + + + + + + 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 aa2da267ca7d..0f2468c44408 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 8eb180bb3a17..b1fea7d27673 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..6fd5344a3c73 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 @@ -1,164 +1,173 @@ - - + + + + + + 2026-02-06T03:28:09.583881 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - + + + + + + - 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 f7d03958c243..6a79ee9d8168 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 5007dc71f21e..18fd01004391 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..f51d2b097574 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 @@ -1,833 +1,863 @@ - - + + + + + + 2026-03-12T18:23:41.217122 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 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 10fbba1d4197..769b843a85fc 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 8f9e41e3d2f8..07acebd2c3ad 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..195521f13d4a 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 @@ -1,571 +1,589 @@ - - + + + + + + 2026-03-12T18:23:41.293675 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - + - - - - - + + - - + - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + 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 e35e01abc8a3..3c6d22a72d27 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 c373eeadb101..9217fd336025 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..fadd75a0ac56 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 @@ -1,310 +1,331 @@ - - + + + + + + 2026-03-12T19:45:18.622647 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - + + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + 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 f7acbc888a26..bd771a073b09 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 05bcb4e7e0df..49ebe9769ce7 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..b9513694b01c 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 @@ -1,429 +1,442 @@ - - + + + + + + 2026-03-12T19:45:18.684691 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + + - - + - - + - + - + - + - + - + - - - - - - - - - - - - - - +M 2009 1063 +L 2009 3309 +Q 1025 3172 1025 2188 +Q 1025 1200 2009 1063 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + 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 2b9620b353fa..5035d1c74b57 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 d0dc862e9b7a..7b1e4567b006 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..fedd7c07a888 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 @@ -1,941 +1,981 @@ - - + + + + + + 2026-03-12T19:45:18.739434 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 04984261d848..57dc6cd2d08e 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 1c5182234f3c..1b8fbf17aa84 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..209189d0660c 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 @@ -1,188 +1,200 @@ - - + + + + + + 2026-03-12T19:45:18.812011 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + 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 8624500b555a..8a469d461e7e 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 614fcc371bf0..46b55de81b9e 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..0946c89c662b 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 @@ -1,188 +1,198 @@ - - + + + + + + 2026-03-12T19:45:18.852833 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - - - +" transform="scale(0.015625)"/> + + + + 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 d6b09fb07dd4..e5a6f52be2e2 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 eee1df5f03f1..6401139b1d08 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..712f6ed9ec6f 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 @@ -1,298 +1,310 @@ - - + + + + + + 2026-03-12T18:23:41.539389 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - + - - - - - - - - - - - - + + + + + + + + + + + + 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 ac5992ecf05d..56fe6dde7243 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 576d98910f3a..0d5bec71ec44 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..a3fcf8cfaed0 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 @@ -1,298 +1,310 @@ - - + + + + + + 2026-03-12T19:45:18.949894 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - + - - - - - - - - - - - - + + + + + + + + + + + + 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 c60e04f00b9d..47896c0a02ab 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 aa51fa90b341..643d07ea5378 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..cebc489345b7 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 @@ -1,171 +1,185 @@ - - + + + + + + 2026-03-12T19:45:19.002815 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - - - - - - - + + + + + + + + + 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 741e8d02d8fd..333ceb589714 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 31340a476478..fd66f0126bd7 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..ec2022476426 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 @@ -1,315 +1,325 @@ - - + + + + + + 2026-03-12T18:23:41.662951 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - - + - - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - 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 cc46c3d9dd61..3a234ec23916 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 31340a476478..e3b57e5361c5 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..d39df295627c 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 @@ -1,315 +1,325 @@ - - + + + + + + 2026-03-12T18:23:41.726187 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - + - - + - - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - 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 0fa74c51c17f..4bf5be17ed0a 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 2d756f3543cf..5540be29bdf1 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..a4a5efee33f5 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 @@ -1,253 +1,252 @@ - - + + + + + + 2026-03-12T19:45:19.182147 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - + - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + 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 d5ef9fe67221..b4006324f403 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 48d2858df579..6664efcd164a 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..1a6571f9b12a 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 @@ -1,340 +1,352 @@ - - + + + + + + 2026-03-12T18:23:41.853424 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - 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 ed7f49eddcd7..7e91620a16bb 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 2be33e80160c..5e71ee019617 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..2b018a08f339 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 @@ -1,187 +1,199 @@ - - + + + + + + 2026-03-12T19:45:19.276894 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 201149a2b9f0..602a88fde2ca 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 2eac76e1335b..d01d7f216370 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..d0d54b8cd8a3 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 @@ - - + + + + + + 2026-03-12T18:23:41.972980 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - +" 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 c6dc587b9ab7..0a8e79106687 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 df90bc37a973..a89a3d912818 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..f17efcecbbd0 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 @@ -1,274 +1,278 @@ - - + + + + + + 2026-03-12T19:45:19.362571 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - 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 10b069caf029..779a9b22e009 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 cde87ba42742..0a34af1bc398 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..8fd8228e84e6 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 @@ -1,535 +1,555 @@ - - + + + + + + 2026-03-12T18:23:42.076563 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - + - - + - - + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 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 38110653cc41..dd6d97b83c02 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 c85cefa08bde..f312adad502d 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..983da2c05335 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 @@ -1,134 +1,145 @@ - - + + + + + + 2026-03-12T19:45:19.495075 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 c4cf7f9c60fd..6105b93c4d21 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 7b59b3908428..96ae035f9bee 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..a84f04384340 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 @@ -1,272 +1,287 @@ - - + + + + + + 2026-03-12T18:23:42.269890 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + 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 2c17ee49f399..42c755201075 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 2a06fab48e5f..778fc59ddf00 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..854d1773c639 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 @@ -1,252 +1,267 @@ - - + + + + + + 2026-03-12T18:23:42.318437 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - + - - - - - - - - - +M 1509 275 +Q 1509 225 1728 225 +L 2472 225 +Q 2828 225 3159 372 +Q 3491 519 3750 775 +Q 3991 1016 4175 1406 +Q 4359 1797 4461 2222 +Q 4563 2647 4563 3003 +Q 4563 3263 4486 3472 +Q 4409 3681 4270 3831 +Q 4131 3981 3922 4064 +Q 3713 4147 3450 4147 +L 2747 4147 +Q 2572 4147 2515 4117 +Q 2459 4088 2413 3928 +L 1538 416 +Q 1509 338 1509 275 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + 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 1c0a5d04e7e6..4595ad7139fb 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 4860243713b5..2f66ad0f670c 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..41db2fbd9df2 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 @@ -1,187 +1,199 @@ - - + + + + + + 2026-03-12T19:45:19.613460 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 40c5e5293a3a..8f1a74a2108c 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 07410dd759c5..b190a7bdf78a 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..d2d9aedb32fc 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 @@ -1,187 +1,199 @@ - - + + + + + + 2026-03-12T19:45:19.662258 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 1d17135d9acf..10633af2df38 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 bf4abb30d884..2dbe39dd6c10 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..8788f49409e8 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 @@ -1,403 +1,417 @@ - - + + + + + + 2026-03-12T18:23:42.445876 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - + - + - - + - - - - - - - - - - - - - +M 1563 1556 +Q 1825 1556 1992 1732 +Q 2159 1909 2234 2171 +Q 2309 2434 2309 2694 +L 2309 2816 +L 2309 2841 +Q 2309 3322 2168 3700 +Q 2028 4078 1631 4078 +Q 1378 4078 1220 3967 +Q 1063 3856 988 3672 +Q 913 3488 892 3278 +Q 872 3069 872 2822 +Q 872 2459 906 2203 +Q 941 1947 1094 1751 +Q 1247 1556 1563 1556 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + 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 1f414e1f6e65..790b7217a4e7 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 3330516c8b8b..b13ffbe696eb 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..fa1b42304649 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 @@ -1,363 +1,382 @@ - - + + + + + + 2026-03-12T18:23:42.495770 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + 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 7d8cf8f9db4a..1ec1626a0ba9 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 7252fb240603..f538072bb196 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..9daf874855d7 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 @@ -1,158 +1,170 @@ - - + + + + + + 2026-03-12T18:23:42.535922 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + 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 7b1e0062fa20..0afefbaae9e8 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 40e26735c6ed..49fbb169d1ef 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..148f2e2bb74c 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 @@ -1,173 +1,186 @@ - - + + + + + + 2026-03-12T19:45:19.865119 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + 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 152b7cc7817b..5b11d6c34d21 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 b2bee6967d8b..922490e26005 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..2717360cc348 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 @@ -1,225 +1,240 @@ - - + + + + + + 2026-03-12T19:45:19.916994 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - - - + - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + 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 27cb88a69050..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 ad4c175bb217..8f72c1e99b90 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..24a8b7d175dd 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 @@ -1,164 +1,181 @@ - - + + + + + + 2026-03-12T19:45:19.970958 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - + + + + + + + + + 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 1447f1a5a6ee..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 cb6c33352136..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 34746a425010..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 5fbff50e3727..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..0b9a6106e5c0 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..a2a946fa6edc 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..f16dcdccad7c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_68.svg @@ -0,0 +1,216 @@ + + + + + + + + 2026-03-12T19:45:20.037345 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..ff0416b3be04 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..e7c45a963c5b 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..c13cedc3b03e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_69.svg @@ -0,0 +1,158 @@ + + + + + + + + 2026-03-12T19:45:20.140719 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..1e4a964cc15d 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..732cf0628cc4 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..c41d6e6bdc4d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_70.svg @@ -0,0 +1,109 @@ + + + + + + + + 2026-03-12T19:45:20.241705 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..d76aa0bebe6c 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..b87943be2d69 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..d8d57d568c7f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_71.svg @@ -0,0 +1,170 @@ + + + + + + + + 2026-03-12T19:45:20.304341 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..6ecea8daa0d7 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..2c8eefa4111f 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..a8c9d56a1f17 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_72.svg @@ -0,0 +1,159 @@ + + + + + + + + 2026-03-12T19:45:20.352411 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..2da8e346731e 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..121e0935b41e 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..510fe456ebe1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_73.svg @@ -0,0 +1,758 @@ + + + + + + + + 2026-03-12T18:23:42.784846 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..2da8e346731e 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..121e0935b41e 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..1272468bba43 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_74.svg @@ -0,0 +1,758 @@ + + + + + + + + 2026-03-12T18:23:42.835481 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..da91d29c79b7 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..cf3c116e4735 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..53aa84c297d9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_75.svg @@ -0,0 +1,333 @@ + + + + + + + + 2026-03-12T18:23:42.896023 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..4978f666a6f5 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..4c609ebe0349 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..a436d7bfbc5f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_76.svg @@ -0,0 +1,307 @@ + + + + + + + + 2026-03-12T19:45:20.629496 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..f0c1af4594ce 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..2cf5e03989ef 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..bba0c8507437 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_78.svg @@ -0,0 +1,306 @@ + + + + + + + + 2026-03-12T18:23:42.984188 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..7c9621a03438 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..d7a00ef0e637 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..de21b07e73e3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_79.svg @@ -0,0 +1,253 @@ + + + + + + + + 2026-03-12T18:23:43.040441 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ca288f6c4028 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..0db9f87782b4 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..69b06d787187 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_80.svg @@ -0,0 +1,592 @@ + + + + + + + + 2026-03-12T19:45:20.761847 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c9fb0c3689fd 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..b30b5849063d 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..c0362abf99db --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_81.svg @@ -0,0 +1,240 @@ + + + + + + + + 2026-03-12T18:23:42.141829 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..65309c1c4faa 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..754033673feb 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..071d16b88333 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_82.svg @@ -0,0 +1,245 @@ + + + + + + + + 2026-03-12T18:23:42.185762 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ac869cb955c1 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..10720d67b3b2 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..75d1f381ef68 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.svg @@ -0,0 +1,199 @@ + + + + + + + + 2026-03-12T19:45:20.937889 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..cddbb9db03ea 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..e1b00e3cdd5d 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..0b16c4d7a14f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_00.svg @@ -0,0 +1,194 @@ + + + + + + + + 2026-03-12T19:45:30.907211 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..fee67fd1dbf1 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..17c7966416e1 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..63936a92bed8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_01.svg @@ -0,0 +1,93 @@ + + + + + + + + 2026-03-12T19:45:30.977578 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..d83fe88bc1af 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..63246ec932ca 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..553b54ce29c4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_02.svg @@ -0,0 +1,173 @@ + + + + + + + + 2026-03-12T19:45:31.044123 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..027564cc57ae 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..7ea40339639f 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..fb058a7c8fe4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_03.svg @@ -0,0 +1,156 @@ + + + + + + + + 2026-03-01T22:41:08.288939 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..178bf86c5caa 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..debe04d51aaf 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..a1256eb81671 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_04.svg @@ -0,0 +1,73 @@ + + + + + + + + 2026-03-12T19:45:31.168141 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + 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..429fe0f1b8c8 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..1800ac42f351 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..b96dbd21be30 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_05.svg @@ -0,0 +1,207 @@ + + + + + + + + 2026-03-12T19:45:31.245645 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..aa80d91a5b5d 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..a74bda85146d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_06.svg @@ -0,0 +1,238 @@ + + + + + + + + 2026-03-12T19:45:31.367336 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ac96d75d1b7b 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..91be4b648b2d 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..342e8da16c1f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_07.svg @@ -0,0 +1,116 @@ + + + + + + + + 2026-03-12T19:45:31.436164 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..9b24ff5dcb24 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..7c9f8f5d033b 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..95b62572d338 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_08.svg @@ -0,0 +1,139 @@ + + + + + + + + 2026-03-12T19:45:31.498339 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..f829d2ee0127 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..5196d8843cab 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..23a318762306 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_09.svg @@ -0,0 +1,79 @@ + + + + + + + + 2026-03-12T19:45:31.558507 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c0227124c950 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..e31134064503 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..c692c5f62aee --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_10.svg @@ -0,0 +1,264 @@ + + + + + + + + 2026-03-12T19:45:31.636698 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..5768c336eff6 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..3e36f7085424 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..f22e10a6ac32 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_11.svg @@ -0,0 +1,225 @@ + + + + + + + + 2026-03-01T22:41:08.620419 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..d3a96c5e13b5 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..e89daeab1efe --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_12.svg @@ -0,0 +1,83 @@ + + + + + + + + 2026-03-12T19:45:31.723262 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..a0e0cce8abc6 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..f7976298d802 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_13.svg @@ -0,0 +1,149 @@ + + + + + + + + 2026-03-12T19:45:31.796593 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..4241ee766e29 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..9c641823feda 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..aabe2587b58b --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_14.svg @@ -0,0 +1,80 @@ + + + + + + + + 2026-03-12T19:45:31.863561 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + 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..f994789c0b3e 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..d1ce614c531c 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..b94f49ae10ba --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_15.svg @@ -0,0 +1,80 @@ + + + + + + + + 2026-03-12T19:45:31.932310 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + 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..0a962e4adfd4 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..2ca13f3592d2 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..a3c306480305 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_16.svg @@ -0,0 +1,98 @@ + + + + + + + + 2026-02-06T03:27:43.428224 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..0a962e4adfd4 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..2ca13f3592d2 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..7cb4809e9edb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_17.svg @@ -0,0 +1,98 @@ + + + + + + + + 2026-02-06T03:27:43.471133 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ae8a2a492d3c 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..d939b9991402 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..b5549fccca3f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_18.svg @@ -0,0 +1,663 @@ + + + + + + + + 2026-02-06T03:27:43.505206 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, 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..0b70a837c67b 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..b8fdb0140624 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..155c0a15f247 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_19.svg @@ -0,0 +1,250 @@ + + + + + + + + 2026-03-01T22:41:08.954312 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..7882dad19384 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..353e0f5f9f00 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..8ddcea5daaa3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_20.svg @@ -0,0 +1,379 @@ + + + + + + + + 2026-03-12T19:45:32.181253 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..54922bdbf740 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..7e3f865003d5 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..c214972f4195 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.svg @@ -0,0 +1,493 @@ + + + + + + + + 2026-02-06T03:27:43.680416 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..a4b8ff8f8321 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..ea3eb7e6e30d 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..3c2deb90b227 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.svg @@ -0,0 +1,314 @@ + + + + + + + + 2026-03-12T19:45:32.299025 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..43eaaf3c1c23 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..930e8d94676d 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..a60a0cea8748 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_24.svg @@ -0,0 +1,88 @@ + + + + + + + + 2026-02-06T03:27:43.779786 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..596f0d74a535 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..0b7502f21524 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..8c30d5b915d1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_25.svg @@ -0,0 +1,119 @@ + + + + + + + + 2026-02-06T03:27:43.814080 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..86427887d955 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..6c5ab90ca378 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..d4c54cc7aa6f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_26.svg @@ -0,0 +1,298 @@ + + + + + + + + 2026-03-12T19:45:32.453200 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..cb46a36fbe0e 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..e0bd8659f019 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.svg @@ -0,0 +1,228 @@ + + + + + + + + 2026-03-12T19:45:32.554027 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..fb14c0531bc9 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..505be62225a9 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..693950295fec --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_28.svg @@ -0,0 +1,220 @@ + + + + + + + + 2026-03-01T22:41:09.297097 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..4272b7e4b582 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..a70ca2bf4583 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..28fe52882681 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_29.svg @@ -0,0 +1,242 @@ + + + + + + + + 2025-11-06T05:24:32.461123 + image/svg+xml + + + Matplotlib v3.11.0.dev1524+g17428e3e2f.d20251106, 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..e956a2898404 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..3111d678d058 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_31.svg @@ -0,0 +1,170 @@ + + + + + + + + 2026-03-12T19:45:32.705054 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..2bf2d681d879 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..78bce2da2736 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..27bba7318e98 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_32.svg @@ -0,0 +1,147 @@ + + + + + + + + 2026-03-01T22:41:09.427787 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..bf4c2cd199e5 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..4e43d4058105 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..ff8c2a37cb86 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_33.svg @@ -0,0 +1,197 @@ + + + + + + + + 2026-03-01T22:41:09.474421 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..4022b3b678eb 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..8c4b0682f4cf 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..8477d83478eb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_35.svg @@ -0,0 +1,150 @@ + + + + + + + + 2026-03-12T19:45:32.880298 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ab92fdf557e8 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..7079b5547cb6 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..86a32825b3de --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_36.svg @@ -0,0 +1,83 @@ + + + + + + + + 2026-02-06T03:27:44.202630 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..975ee58d62b7 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..436d973b22ca 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..508f4b12731a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_37.svg @@ -0,0 +1,553 @@ + + + + + + + + 2026-03-01T22:41:08.196210 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..fb9a31d34749 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..ffd2c46771a5 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..ef021e3cfc47 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_38.svg @@ -0,0 +1,333 @@ + + + + + + + + 2026-02-06T03:27:44.417859 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..5c70006488a3 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..f8062586d021 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..5ea3c107f591 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_39.svg @@ -0,0 +1,255 @@ + + + + + + + + 2026-03-12T19:45:33.112144 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..b3611f378566 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..6006f45ddb9d 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..497af9c69396 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_40.svg @@ -0,0 +1,246 @@ + + + + + + + + 2026-03-12T19:45:33.175177 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..bd49ac5bbe98 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..77e5b2024d0c 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..3f58c207708b --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_41.svg @@ -0,0 +1,557 @@ + + + + + + + + 2026-03-12T19:45:33.234601 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..adf1fcd2fda2 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..50bcce6e3192 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_42.svg @@ -0,0 +1,99 @@ + + + + + + + + 2026-03-12T19:45:33.315970 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..0df0cf0814c9 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..da7bf90b4a9d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_43.svg @@ -0,0 +1,111 @@ + + + + + + + + 2026-03-12T19:45:33.401621 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..7df1eddeec51 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..47b8a5b1dd12 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..776a7620abb3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_44.svg @@ -0,0 +1,152 @@ + + + + + + + + 2026-02-06T03:27:44.678330 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..8a4ebbcb65c0 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..26c0da632ace 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..d063832cb85b --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_45.svg @@ -0,0 +1,152 @@ + + + + + + + + 2026-03-12T19:45:33.494464 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..1c2aaae4ea5d 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..ff2aff82e516 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..d57cc59e2fea --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.svg @@ -0,0 +1,150 @@ + + + + + + + + 2026-03-12T19:45:33.558532 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..47aa2b36fb4f 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..3feb6c7acf86 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..a1d335aa315f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_47.svg @@ -0,0 +1,247 @@ + + + + + + + + 2026-03-01T22:41:08.671724 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..696da091a36b 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..1cfb41f2ece5 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..1f178ac96d90 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_48.svg @@ -0,0 +1,247 @@ + + + + + + + + 2026-03-01T22:41:08.744990 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..1b6721707126 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..da791933e94d 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..8ab82619f2ad --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.svg @@ -0,0 +1,135 @@ + + + + + + + + 2026-02-06T03:27:44.940192 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..b7bb643ac250 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..73f4d6e17096 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..a5d446c4af08 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_50.svg @@ -0,0 +1,204 @@ + + + + + + + + 2026-03-01T22:41:08.861980 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..02868b361561 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..6a9b680c86cf 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..cf81de016e3a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_51.svg @@ -0,0 +1,98 @@ + + + + + + + + 2026-03-12T19:45:33.942782 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..b89de97adf5c 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..cbb4ae410be2 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..1d36984d47f5 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_52.svg @@ -0,0 +1,326 @@ + + + + + + + + 2026-02-06T03:27:45.094929 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, 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..ff37316820e3 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..a3b4870454a6 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..b5549aaeac71 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_53.svg @@ -0,0 +1,202 @@ + + + + + + + + 2026-03-12T19:45:34.102831 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..8ca1b3e84816 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..08532af985a4 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..73ae09135a64 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_54.svg @@ -0,0 +1,312 @@ + + + + + + + + 2026-03-01T22:41:09.074987 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..d9289748d57a 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..4522663c38ba 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..03aec7bef335 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_55.svg @@ -0,0 +1,82 @@ + + + + + + + + 2026-03-12T19:45:34.381199 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..8925b299ae2c 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..90dcaaa0540d 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..c1ba69775adb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_56.svg @@ -0,0 +1,172 @@ + + + + + + + + 2026-03-01T22:41:09.199398 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..5ac544137c15 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..454ef847991a 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..4b8edf732bb8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_57.svg @@ -0,0 +1,144 @@ + + + + + + + + 2026-02-06T03:27:45.380556 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..fd63922f3f29 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..944145cff410 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..5a34f31986fa --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_58.svg @@ -0,0 +1,98 @@ + + + + + + + + 2026-03-12T19:45:34.574136 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..eb35334267a1 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..db27e6f868f7 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..a6cb2791b213 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_59.svg @@ -0,0 +1,98 @@ + + + + + + + + 2026-03-12T19:45:34.643944 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..06804ff29439 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..c3ca67928045 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..a02ccef313f4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.svg @@ -0,0 +1,246 @@ + + + + + + + + 2026-02-06T03:27:45.503956 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..3f07979d5f3d 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..c559a9c73ff9 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..858fe07d74c9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_61.svg @@ -0,0 +1,217 @@ + + + + + + + + 2026-02-06T03:27:45.551214 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..3698c773e66e 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..acd0123a4aa3 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..1ec0117196bc --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_62.svg @@ -0,0 +1,107 @@ + + + + + + + + 2026-02-06T03:27:45.605807 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..5cdc809517f9 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..5d3bd5df66bb 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..f2d257fff69e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_63.svg @@ -0,0 +1,119 @@ + + + + + + + + 2026-03-12T19:45:34.843935 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..1e0c9fbb4b6c 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..03c4cb56c2c3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_64.svg @@ -0,0 +1,177 @@ + + + + + + + + 2026-03-12T19:45:34.927798 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..120338b4d0b9 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..daaeb48b4bc7 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..3fb441b44b89 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_65.svg @@ -0,0 +1,130 @@ + + + + + + + + 2026-03-12T19:45:34.984126 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..49511753595a 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..703233f71967 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..eb999887a311 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_68.svg @@ -0,0 +1,184 @@ + + + + + + + + 2026-03-01T22:41:09.555342 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, 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..e78cde0fff18 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..2eda2926bd3b 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..c2323ebc1e28 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_69.svg @@ -0,0 +1,114 @@ + + + + + + + + 2026-03-12T19:45:35.127335 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..6e1851eb44b9 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..5e082b25b331 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_70.svg @@ -0,0 +1,67 @@ + + + + + + + + 2026-03-12T19:45:35.217120 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..6c942b6ed538 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..98ef98370d21 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..ac4ff753e3ad --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_71.svg @@ -0,0 +1,151 @@ + + + + + + + + 2026-03-12T19:45:35.284542 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..457c86f68a2e 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..e0a04c596d67 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..7d1f7d02ce7a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_72.svg @@ -0,0 +1,131 @@ + + + + + + + + 2026-03-12T19:45:35.353838 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c0050faff8d0 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..0999d4a1c407 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..dd5aca067b8e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_73.svg @@ -0,0 +1,371 @@ + + + + + + + + 2026-02-06T03:27:45.941791 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c0050faff8d0 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..0999d4a1c407 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..bdd16a8928cf --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_74.svg @@ -0,0 +1,371 @@ + + + + + + + + 2026-02-06T03:27:46.015591 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..19858f2ca3b4 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..e18f4b8c8b9d 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..331fad2ceaea --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_75.svg @@ -0,0 +1,161 @@ + + + + + + + + 2026-02-06T03:27:46.092688 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..18bc4e341133 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..b94caa0b1c03 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_76.svg @@ -0,0 +1,262 @@ + + + + + + + + 2026-03-12T19:45:35.653869 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..675d81771185 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..e8df5381165a 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..b0996eb5d481 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_78.svg @@ -0,0 +1,211 @@ + + + + + + + + 2026-02-06T03:27:46.208916 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dd4e5687159a 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..e05f7d8681e4 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..d121cb8392e0 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_79.svg @@ -0,0 +1,151 @@ + + + + + + + + 2026-03-01T22:41:08.758679 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..0723f0a4973d 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..ada051d59e1e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_80.svg @@ -0,0 +1,413 @@ + + + + + + + + 2026-03-12T19:45:35.860893 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..2e4af8dceb3b 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..10ce3a709b86 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..2f0a68d1c45d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_81.svg @@ -0,0 +1,154 @@ + + + + + + + + 2026-02-06T03:27:46.350914 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..f0a8ffafae8a 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..4da2d0c923d2 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..2e8e43046cd6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_82.svg @@ -0,0 +1,156 @@ + + + + + + + + 2026-03-01T22:41:08.903086 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..bd803cc4faef 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..a5131a0b972a 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..c32dfdc8a7e6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.svg @@ -0,0 +1,159 @@ + + + + + + + + 2026-03-12T19:45:36.098751 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..1e1daa4d69e2 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..46bff17e9a01 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..b5e1d1e0aa12 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_00.svg @@ -0,0 +1,198 @@ + + + + + + + + 2026-03-12T19:45:36.166686 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..48124bd6baf3 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..15dcf4b18dd4 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..4f089111ec4c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_01.svg @@ -0,0 +1,108 @@ + + + + + + + + 2026-03-12T19:45:36.242039 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c2ef41fd1553 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..1554613d0f53 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..2a395fc1a926 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_02.svg @@ -0,0 +1,183 @@ + + + + + + + + 2026-03-12T19:45:36.288689 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..a88a4913915b 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..0e5ece84f1ad 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..a6af5f86c843 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_03.svg @@ -0,0 +1,169 @@ + + + + + + + + 2026-03-01T22:41:09.097637 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..3b24e9ae183f 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..a4f1c1aa63f8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_04.svg @@ -0,0 +1,84 @@ + + + + + + + + 2026-03-12T19:45:36.401195 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + 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..30579f332db8 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..22a7262cae6c 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..6e178ada9260 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_05.svg @@ -0,0 +1,228 @@ + + + + + + + + 2026-03-12T19:45:36.463090 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..8fc84c16dae0 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..a72575f10796 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..66e9acf7c023 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_06.svg @@ -0,0 +1,251 @@ + + + + + + + + 2026-03-12T19:45:36.533998 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..3579ed64b1b1 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..82a65374b39a 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..15b8226375af --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_07.svg @@ -0,0 +1,127 @@ + + + + + + + + 2026-03-12T19:45:36.602737 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..06b473a6de29 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..7a708c9848bf 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..20d2ffc1b05f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_08.svg @@ -0,0 +1,190 @@ + + + + + + + + 2026-03-12T19:45:36.679046 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..8400423d45ef 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..532979de50cb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_09.svg @@ -0,0 +1,90 @@ + + + + + + + + 2026-03-12T19:45:36.762667 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..56d567c82c10 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..9e6611d68129 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_10.svg @@ -0,0 +1,282 @@ + + + + + + + + 2026-03-12T19:45:36.828195 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..372c131fb37e 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..eb877e64a375 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..deff728a5515 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_11.svg @@ -0,0 +1,240 @@ + + + + + + + + 2026-03-01T22:41:09.416361 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..fcac2f5fd6ff 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..aac33a6443ce --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_12.svg @@ -0,0 +1,87 @@ + + + + + + + + 2026-03-12T19:45:36.966905 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ca2e875d79dd 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..3270fc15f0ec --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_13.svg @@ -0,0 +1,175 @@ + + + + + + + + 2026-03-12T19:45:37.070554 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..473d096c04da 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..f606c5bc0e32 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..7e505c6c0b7a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_14.svg @@ -0,0 +1,85 @@ + + + + + + + + 2026-03-12T19:45:37.129450 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + 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..44c76b46814e 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..6d324ec511fa 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..6a58b19a88a4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_15.svg @@ -0,0 +1,85 @@ + + + + + + + + 2026-03-12T19:45:37.192257 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + 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..7eeeef9a4100 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..d470b47f7b75 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..78ec6de323dc --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_16.svg @@ -0,0 +1,110 @@ + + + + + + + + 2026-03-12T18:23:45.059198 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..7eeeef9a4100 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..d470b47f7b75 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..1e9fc844d449 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_17.svg @@ -0,0 +1,110 @@ + + + + + + + + 2026-03-12T18:23:45.095616 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..2f44bf167851 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..e3e0d8108c52 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..ba5433325497 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_18.svg @@ -0,0 +1,744 @@ + + + + + + + + 2026-03-12T18:23:44.761692 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, 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..5f9cb1265658 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..23f361e967eb 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..434453e8035d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_19.svg @@ -0,0 +1,266 @@ + + + + + + + + 2026-03-01T22:41:09.279557 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..6f282bd389ed 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..c30474d51bf9 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..567a43fc3830 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_20.svg @@ -0,0 +1,434 @@ + + + + + + + + 2026-03-12T19:45:37.536844 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ea8f9a00581e 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..6d555cf1a97a 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..93d41406bf08 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.svg @@ -0,0 +1,550 @@ + + + + + + + + 2026-03-12T18:23:44.906466 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..defdd37390ec 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..6246da33df66 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..6c3905aa8771 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.svg @@ -0,0 +1,324 @@ + + + + + + + + 2026-03-12T19:45:37.727953 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..90b455091ed8 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..3ce5f1540491 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..8c1ff3187d7c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_24.svg @@ -0,0 +1,108 @@ + + + + + + + + 2026-02-06T03:27:47.407411 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..3b8a5dcd0b85 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..3fb61f10a7af 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..1f682b3b447d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_25.svg @@ -0,0 +1,139 @@ + + + + + + + + 2026-02-06T03:27:47.466174 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..d9544dbf6e48 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..a059ce7b6555 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..b54796907fd5 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_26.svg @@ -0,0 +1,293 @@ + + + + + + + + 2026-03-12T19:45:37.906996 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..6a43478d77a6 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..ee209bc5c479 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_27.svg @@ -0,0 +1,255 @@ + + + + + + + + 2026-03-12T19:45:38.002359 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c2dd0e1a0c6c 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..01f131caf56e 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..6d1ad4bbcdd5 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_28.svg @@ -0,0 +1,243 @@ + + + + + + + + 2026-03-12T18:23:45.102048 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..aab73b24bd03 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..257d53d559e2 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..3fd2430bec77 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_29.svg @@ -0,0 +1,290 @@ + + + + + + + + 2025-11-06T05:24:32.504363 + image/svg+xml + + + Matplotlib v3.11.0.dev1524+g17428e3e2f.d20251106, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..264fd511a8ca 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..11602fa13113 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..6a1fe09b88a5 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_31.svg @@ -0,0 +1,200 @@ + + + + + + + + 2026-03-12T19:45:38.212209 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..41049665366f 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..82033764378c 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..403759d080b2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_32.svg @@ -0,0 +1,159 @@ + + + + + + + + 2026-03-01T22:41:09.782099 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..d870ed0cdea2 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..6d0ff3f35a2d 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..5a13519d002e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_33.svg @@ -0,0 +1,230 @@ + + + + + + + + 2026-03-12T18:23:45.249177 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ce98d778daf1 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..13cc97b8a09f 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..48670fdb55c6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_35.svg @@ -0,0 +1,158 @@ + + + + + + + + 2026-03-12T19:45:38.390972 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..0d56b0304a2e 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..7f297d2d1405 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..feb67cf684fc --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_36.svg @@ -0,0 +1,111 @@ + + + + + + + + 2026-02-06T03:27:47.901504 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..9922c68169cf 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..971305db6f12 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..d390af47b6b7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_37.svg @@ -0,0 +1,604 @@ + + + + + + + + 2026-03-12T18:23:45.341770 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ef7807608d20 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..e7e8c894e7e3 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..70294951c2a9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_38.svg @@ -0,0 +1,367 @@ + + + + + + + + 2026-02-06T03:27:48.405077 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..cfa494e86cd8 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..a6dccc0bf676 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..283a65b0e197 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_39.svg @@ -0,0 +1,246 @@ + + + + + + + + 2026-03-12T19:45:38.704084 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..8890bfefd980 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..538f14c4b1b4 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..7a167615f941 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_40.svg @@ -0,0 +1,358 @@ + + + + + + + + 2026-03-12T19:45:38.803339 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..f34851b7b303 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..465e9cfa7852 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..7505bcb464b3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_41.svg @@ -0,0 +1,661 @@ + + + + + + + + 2026-03-12T19:45:38.881017 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..9da375759fa7 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..aa07f3cae37f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_42.svg @@ -0,0 +1,111 @@ + + + + + + + + 2026-03-12T19:45:38.960348 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..42190c1a8ffe 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..9389d6f7d785 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_43.svg @@ -0,0 +1,126 @@ + + + + + + + + 2026-03-12T19:45:39.027536 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..30b9ffe095aa 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..932d35bda07c 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..71f1a5cfe566 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_44.svg @@ -0,0 +1,172 @@ + + + + + + + + 2026-03-12T18:23:45.655056 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..80f063dccf3e 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..a3bc9c850626 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..507bc39bbcc6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_45.svg @@ -0,0 +1,172 @@ + + + + + + + + 2026-03-12T19:45:39.160784 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..f33d669d5b5c 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..632e2a612c37 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..5e79df4de605 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_46.svg @@ -0,0 +1,140 @@ + + + + + + + + 2026-03-12T19:45:39.253949 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..0901edeacebd 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..ad7eeff5468a 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..3fdb68ffb460 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_47.svg @@ -0,0 +1,243 @@ + + + + + + + + 2026-03-01T22:41:09.623109 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..e9da904ccbbf 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..00ef107b3347 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..06393639c2b5 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_48.svg @@ -0,0 +1,243 @@ + + + + + + + + 2026-03-12T18:23:44.594908 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..9ba210a65bdc 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..09edf2938521 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..c335690bc9cb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_49.svg @@ -0,0 +1,146 @@ + + + + + + + + 2026-02-06T03:27:48.971539 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..d6326759b9ac 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..d9214331adb8 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..52236c500f16 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_50.svg @@ -0,0 +1,216 @@ + + + + + + + + 2026-03-12T18:23:44.700424 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..4c2ddb1c718a 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..61207d49fd40 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..741e23d9d1fd --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_51.svg @@ -0,0 +1,110 @@ + + + + + + + + 2026-03-12T19:45:39.543673 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..e5229213cf55 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..38a495f30837 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..2b82f8e905a0 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_52.svg @@ -0,0 +1,353 @@ + + + + + + + + 2026-03-12T18:23:44.802692 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, 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..efd5c0acced0 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..f4fb6f0aeafb 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..43c89409c7d1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_53.svg @@ -0,0 +1,206 @@ + + + + + + + + 2026-03-12T19:45:39.663153 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..0b0a345c21c4 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..ca01422d80ba 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..f0a3641f29e8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_54.svg @@ -0,0 +1,344 @@ + + + + + + + + 2026-03-12T18:23:44.902951 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..a0f9d1c0545c 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..9f52dcd86872 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..580e0595b5f0 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_55.svg @@ -0,0 +1,87 @@ + + + + + + + + 2026-03-12T19:45:39.828128 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..226afcab6fbf 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..463b35b59841 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..c108d51a23bf --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_56.svg @@ -0,0 +1,191 @@ + + + + + + + + 2026-03-01T22:41:10.115407 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..41ca025e4911 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..05ba1c642ea2 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..0e3d39b1f861 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_57.svg @@ -0,0 +1,186 @@ + + + + + + + + 2026-02-06T03:27:49.427510 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..9e34c1ae65e9 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..54229de1aa67 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..54992f3ed508 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_58.svg @@ -0,0 +1,110 @@ + + + + + + + + 2026-03-12T19:45:40.006036 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..39274f581c50 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..972a6b68af4d 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..b5e5cbf18e83 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_59.svg @@ -0,0 +1,110 @@ + + + + + + + + 2026-03-12T19:45:40.071622 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..e90dbadf0230 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..fbd56b9a151b 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..170433d82d38 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.svg @@ -0,0 +1,260 @@ + + + + + + + + 2026-03-12T18:23:45.143308 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..2d4da3882b69 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..25c8ab1d1f77 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..187e027b2f4f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_61.svg @@ -0,0 +1,233 @@ + + + + + + + + 2026-03-12T18:23:45.197049 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ee8baefd9a8e 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..6cea80336795 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..72072be26fce --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_62.svg @@ -0,0 +1,116 @@ + + + + + + + + 2026-03-12T18:23:45.248902 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c1a81c5f7897 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..0be5a5597fb7 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..5934f9d0a625 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_63.svg @@ -0,0 +1,122 @@ + + + + + + + + 2026-03-12T19:45:40.287591 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..d4ea1d516903 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..90f1bb73fb70 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_64.svg @@ -0,0 +1,167 @@ + + + + + + + + 2026-03-12T19:45:40.341857 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..996d2c9284cd 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..db252bdc05b2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_65.svg @@ -0,0 +1,138 @@ + + + + + + + + 2026-03-12T19:45:40.390888 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..32506970502f 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..3338fa2a4967 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..8aa7e1047c04 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_68.svg @@ -0,0 +1,173 @@ + + + + + + + + 2026-03-01T22:41:10.441309 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, 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..ad0f71db21d5 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..a91dcd79b67b 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..f00675c6a3bd --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_69.svg @@ -0,0 +1,128 @@ + + + + + + + + 2026-03-12T19:45:40.509413 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..19abc015e82d 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..2e47a0bc175f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_70.svg @@ -0,0 +1,79 @@ + + + + + + + + 2026-03-12T19:45:40.572323 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..64e9d66b2d2e 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..ff17cdfdc63c 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..7aa0e1b9e0d1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_71.svg @@ -0,0 +1,151 @@ + + + + + + + + 2026-03-12T19:45:40.640954 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..b236ab6c24ff 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..db76a7451c0d 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..081f2335f169 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_72.svg @@ -0,0 +1,159 @@ + + + + + + + + 2026-03-12T19:45:40.695091 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..f5ca26fd36a7 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..4b2efcc5cc7e 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..a08ce03f6cdc --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_73.svg @@ -0,0 +1,441 @@ + + + + + + + + 2026-03-12T18:23:45.545213 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..f5ca26fd36a7 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..4b2efcc5cc7e 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..f851229b04b9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_74.svg @@ -0,0 +1,441 @@ + + + + + + + + 2026-03-12T18:23:45.592970 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..aeff66cae14c 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..ce1c4fca3131 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..a773b76ea91e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_75.svg @@ -0,0 +1,205 @@ + + + + + + + + 2026-03-12T18:23:45.670589 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..9b4760229af2 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..0d507998e882 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_76.svg @@ -0,0 +1,265 @@ + + + + + + + + 2026-03-12T19:45:40.929139 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..015e1cff67ee 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..14ba098da97b 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..5840578ddefc --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_78.svg @@ -0,0 +1,215 @@ + + + + + + + + 2026-03-12T18:23:45.015990 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..24735ecb00e8 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..b21e1405ab4c 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..5e1691850a12 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_79.svg @@ -0,0 +1,174 @@ + + + + + + + + 2026-03-12T18:23:45.071114 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..21999478e67f 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..a12653662cb0 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..2879f1e01f54 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_80.svg @@ -0,0 +1,431 @@ + + + + + + + + 2026-03-12T19:45:41.104915 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c915b6d8325a 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..f35cd504ded3 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..654467ad9f33 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_81.svg @@ -0,0 +1,159 @@ + + + + + + + + 2026-03-12T18:23:45.163364 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..d7edf0bfeec0 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..ecbf4e7b7a19 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..1a95b5f11dd7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_82.svg @@ -0,0 +1,169 @@ + + + + + + + + 2026-03-12T18:23:45.209401 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ef60c97ba001 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..dc667fa0cd4d 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..41f241300b63 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.svg @@ -0,0 +1,148 @@ + + + + + + + + 2026-03-12T19:45:41.245728 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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 dd1e747c012f..98095a0152ac 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 5603c642d00f..3c3d5368e2d0 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..0436c89157e7 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 @@ -1,187 +1,203 @@ - - + + + + + + 2026-03-12T19:45:20.984463 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - + - + - - - - - - - - - - - - - +M 2483 1958 +Q 2483 2509 2035 2509 +Q 1594 2509 1158 1773 +Q 954 1427 826 1008 +Q 698 589 698 294 +Q 698 77 992 77 +Q 1414 77 1779 454 +Q 2074 762 2278 1187 +Q 2483 1613 2483 1958 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + 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 2d1b7be4c3e4..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 017c8acf1b96..4ad548790a92 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..0af0829bda8d 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 @@ -1,181 +1,147 @@ - - + + + + + + 2026-03-12T19:45:21.049210 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - + + - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 65ca417cf1ca..be15f45ffa51 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 e3b60a790fce..ef95af865027 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..32092496f644 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 @@ -1,159 +1,174 @@ - - + + + + + + 2026-03-12T19:45:21.094737 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" 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)"/> + + + + + + + + + + + + + + + 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 3264a12ce946..f76260f6fac2 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 1089ba52bc39..760a55cd9d5d 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..5c74dbab2cdb 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 @@ -1,170 +1,186 @@ - - + + + + + + 2026-03-12T18:23:42.348451 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + + 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 5a45b3bdf259..cbc84a278ce3 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..b30f7b203f17 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 @@ -1,111 +1,123 @@ - - + + + + + + 2026-03-12T19:45:21.194946 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - + + + + + + + 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 ab435eb22611..bd78e4e8bc6c 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 f4bea46f5e4e..4433f1940134 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..471b6767198c 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 @@ - - + + + + + + 2026-03-12T19:45:21.234377 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - + - - - + + - - - - - - - - - - - - - - - - - - - - - +M 4077 768 +L 307 768 +L 307 1190 +L 4077 1190 +L 4077 768 +z +" 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 e39f7c0bebd0..6fe937ff6a91 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 dd316e61b24e..298d16f1b691 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..989d0dfc5f91 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 @@ -1,322 +1,343 @@ - - + + + + + + 2026-03-12T19:45:21.295418 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - + - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + 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 f44493f75223..d0f80a99a8a8 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 bd84fc4fe1d3..f001f43c3c6d 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..b48380ed1c1a 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 @@ -1,159 +1,171 @@ - - + + + + + + 2026-03-12T19:45:21.355683 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + + - - - + - + - - - - - - - - - - - +M 2502 2579 +L 1082 2579 +L 1792 659 +L 2502 2579 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + 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 5e74f3896581..c932ff17f08b 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 fdbda41961e4..d8f9a58f06e5 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..162ba7a86e91 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 @@ -1,230 +1,242 @@ - - + + + + + + 2026-03-12T19:45:21.399349 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - + - + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + 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 05aee85da38f..5b3884347921 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 1e0694ae3980..1bcbd6194292 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..16acd787f72c 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 @@ -1,117 +1,129 @@ - - + + + + + + 2026-03-12T19:45:21.456219 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - + + + + + + + + + + + + + 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 1a9d43df118c..4b55d1cd1c98 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..b2cfb68bd25f 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 @@ -1,261 +1,280 @@ - - + + + + + + 2026-03-12T19:45:21.497422 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - + - - - - - - - - - - +M 979 2035 +L 979 474 +Q 979 326 1161 233 +Q 1344 141 1600 141 +Q 1978 141 2195 416 +Q 2432 710 2432 1261 +Q 2432 1888 2182 2240 +Q 1971 2541 1613 2541 +Q 1357 2541 1168 2390 +Q 979 2240 979 2035 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + 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 500fe66af1c1..5397c88df8f8 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 da4e26f8da8f..ae442a82d87d 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..de592af14883 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 @@ -1,227 +1,240 @@ - - + + + + + + 2026-03-01T22:41:06.888772 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - - - + - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - 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 ed7777567b8f..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 575d546d8377..ea166d922e71 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..797ba5b1e80e 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 @@ -1,99 +1,112 @@ - - + + + + + + 2026-03-12T19:45:21.588161 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - + + + + + + + + + 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 e2fba2c16712..54c035263024 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..95046b4144a9 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 @@ -1,198 +1,213 @@ - - + + + + + + 2026-03-12T19:45:21.647240 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - + - - - - - - - - - - - +M 1619 0 +L 102 0 +L 102 96 +Q 435 115 521 211 +Q 608 307 608 666 +L 608 2118 +Q 608 2342 563 2432 +Q 518 2522 397 2522 +Q 243 2522 128 2490 +L 128 2592 +L 1120 2944 +L 1146 2918 +L 1146 672 +Q 1146 314 1226 218 +Q 1306 122 1619 96 +L 1619 0 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + 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 1b1054a48194..d1eec62c0a1c 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 0cc4680a2566..3bf942507d35 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..2b60ce5b743b 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 @@ -1,100 +1,111 @@ - - + + + + + + 2026-03-12T19:45:21.704144 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - - +" transform="scale(0.015625)"/> + + + + 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 c3d965af844c..1037902fc134 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 d11ed0229ebf..4e3b8cd2f403 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..be0b86c7384d 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 @@ -1,100 +1,111 @@ - - + + + + + + 2026-03-12T19:45:21.770334 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - - +" transform="scale(0.015625)"/> + + + + 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 ad296809129d..442c78a370c2 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 38ec6b162d21..8535558fd977 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..af27c0d4d72b 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 @@ -1,136 +1,148 @@ - - + + + + + + 2026-03-12T18:23:42.819221 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 2781de772c95..442c78a370c2 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 38ec6b162d21..8535558fd977 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..4166c8caa3a2 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 @@ -1,136 +1,148 @@ - - + + + + + + 2026-03-12T18:23:42.851960 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 b0febb12bc26..a066038b18a0 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 81f9407c6072..0075ebdc938a 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..ddb0270a7f92 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 @@ - - + + + + + + 2026-03-12T18:23:42.887624 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 d1139b531330..fa84893f33bf 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 77e10f405a1f..8c81db3a3427 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..4cabdf948241 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 @@ -1,287 +1,300 @@ - - + + + + + + 2026-03-01T22:41:07.327883 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + + - - - - - + - - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - 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 0ad2344a49b3..bd8904ae911f 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 d2769ab32270..e054a651454f 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..d6f94e1a6d6a 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 @@ -1,499 +1,519 @@ - - + + + + + + 2026-03-12T19:45:22.029095 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - + - + + - + - - + - + - - - - - - + - + - + - - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 d618b1b8f7c5..e8b32b3c12c1 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 42ce0cd8de28..da5b8cd6b1ee 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..46873bff2161 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 @@ -1,565 +1,587 @@ - - + + + + + + 2026-03-12T18:23:43.070585 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 ccc6129a9fb2..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 f2e9c18dc4dc..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 7068a20b305e..a59ffeecff8b 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 93b52d42f35c..56440aea8006 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..ea7263b59363 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 @@ -1,308 +1,329 @@ - - + + + + + + 2026-03-12T19:45:22.147293 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - + - + - + - - - - + - - - + - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + + 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 8b797090e721..e0efca0f30a2 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 df574259ed1f..dbe02cc6e55b 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..904a7be34cdf 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 @@ -1,103 +1,116 @@ - - + + + + + + 2026-03-12T18:23:43.146734 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - + - - - - - +M 1574 2803 +L 909 179 +Q 710 -595 419 -960 +Q 128 -1325 -288 -1325 +Q -512 -1325 -653 -1216 +Q -794 -1107 -794 -934 +Q -794 -819 -717 -736 +Q -640 -653 -531 -653 +Q -282 -653 -282 -890 +Q -282 -966 -320 -1014 +Q -358 -1062 -358 -1107 +Q -358 -1184 -243 -1184 +Q -51 -1184 80 -934 +Q 211 -685 378 -19 +L 838 1850 +Q 941 2266 941 2362 +Q 941 2470 873 2515 +Q 806 2560 634 2560 +L 467 2560 +L 467 2662 +Q 755 2682 1549 2822 +L 1574 2803 +z +" transform="scale(0.015625)"/> + + + + + 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 4f5599d2b2ed..d17045b3df9e 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 d490866595f2..3909e5734a69 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..4b8245467fed 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 @@ -1,138 +1,151 @@ - - + + + + + + 2026-03-12T18:23:43.178911 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - + - + - - - - - - - +M 1421 730 +L 1504 659 +Q 1235 243 1049 86 +Q 864 -70 627 -70 +Q 314 -70 314 282 +Q 314 467 454 992 +L 762 2125 +Q 819 2330 819 2406 +Q 819 2502 745 2528 +Q 672 2554 410 2560 +L 410 2662 +Q 704 2688 1434 2822 +L 1459 2803 +L 858 608 +Q 794 390 794 326 +Q 794 230 883 230 +Q 1043 230 1421 730 +z +" transform="scale(0.015625)"/> + + + + + + + + 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 c19194d9bc37..cae8b8afbb50 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 c6c263a2f6d4..1970fe9a0e7a 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..e98ee54ed260 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 @@ - - + + + + + + 2026-03-12T19:45:22.253375 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - + - - - - - - + - - - - - - - - - - - - - - - - - +" 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 ce7ed4040ee6..2128e70a3d08 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 cbeeb6ae532d..6c12223e0ac0 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..b963d9de0dc9 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 @@ -1,279 +1,300 @@ - - + + + + + + 2026-03-12T19:45:22.329196 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - + + - - - - - - - - - - - - - - - - - - - +M 1837 813 +L 1837 1715 +Q 1248 1510 1018 1293 +Q 800 1094 800 800 +Q 800 557 921 432 +Q 1043 307 1242 307 +Q 1453 307 1613 410 +Q 1747 506 1792 589 +Q 1837 672 1837 813 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + 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 3b02f03355f3..5905f8b92e3f 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 bd6f0b0cbceb..f85068097c86 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..21455f2b159f 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 @@ -1,272 +1,289 @@ - - + + + + + + 2026-03-12T18:23:43.309363 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - 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 b2786a4f9c1f..db026d6d0c51 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 8f8a0fca3b58..e896de0f440c 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..e9026530a731 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 @@ -1,342 +1,360 @@ - - + + + + + + 2026-03-12T19:45:22.414040 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - - - - + - - + - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + 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 4a349dfb41c2..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 9e8f5fadc268..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 0ce8d3de6f12..a641f635743c 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 e6be125b5888..3d42196224e6 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..7ff7342be431 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 @@ -1,77 +1,239 @@ - - + + + + + + 2026-03-12T19:45:22.470536 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - + - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + 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 cc359bcac523..d9b64e817d4c 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 bef5aa836462..fd6a8f541f24 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..e0fc61801301 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 @@ -1,182 +1,196 @@ - - + + + + + + 2026-03-12T18:23:43.420583 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - + + - - - - - - - - - + + + + + + + + + + + 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 b39ae56660c6..55b48114fe7d 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 20df046ba697..464ec65fec8b 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..22e7f44dcc36 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 @@ -1,234 +1,243 @@ - - + + + + + + 2026-03-12T18:23:43.464061 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + + - - + - + - + - + - - - - - - - - - - - + + + + + + + + + + - 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 96a420ed9234..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 5afaa02dd09c..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 d9e056533fae..37f7d8a47c9c 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 db9656bae3f1..fe82d7cb3191 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..6abaf9885bc4 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 @@ -1,170 +1,181 @@ - - + + + + + + 2026-03-01T22:41:07.934040 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - - + + - - - - - - - - + + + + + + + + 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 15a47c2ade35..5f8027f47c5a 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 63f6f7c11259..888f7db6368e 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..5e14081e718d 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 @@ -1,120 +1,128 @@ - - + + + + + + 2026-02-06T03:28:13.635555 + image/svg+xml + + + Matplotlib v3.11.0.dev1856+ga22069c80c, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - - - + + + + + - 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 ee799c0978d1..3576ea446a4d 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 65cd43cc8e0e..a7f624ce14f3 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..725a7cae4638 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 @@ -1,649 +1,674 @@ - - + + + + + + 2026-03-12T18:23:43.643873 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 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 a420868eb87e..99b5776ebfb3 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 42b8623a8ad3..ddde439a05d5 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..dd21fc9bd3a8 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 @@ -1,398 +1,416 @@ - - + + + + + + 2026-03-12T18:23:43.734722 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - + - + - + - - - - - - + - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + 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 e0857671bdfe..6f8a21bf1c03 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 c41fcd9c8f43..d9f334bc7855 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..16eb9a38ddfd 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 @@ -1,255 +1,273 @@ - - + + + + + + 2026-03-12T19:45:22.824783 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - + - - - - - + - - - - - - - - - - +M 2483 1958 +Q 2483 2509 2035 2509 +Q 1594 2509 1158 1773 +Q 954 1427 826 1008 +Q 698 589 698 294 +Q 698 77 992 77 +Q 1414 77 1779 454 +Q 2074 762 2278 1187 +Q 2483 1613 2483 1958 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + 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 8b58bc70031d..0622ad5585f7 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 ff81b4c48959..d000d4053ab5 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..ed39a952fedc 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 @@ -1,397 +1,415 @@ - - + + + + + + 2026-03-12T19:45:22.895587 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - + - - - - - - + + - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + 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 4dbfadaa0c9c..1bbc1bb6e617 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 16ba2960967e..a6b3b627e19b 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..4f0e586bd067 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 @@ -1,750 +1,782 @@ - - + + + + + + 2026-03-12T19:45:22.960409 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 a87da4a640fb..3e8d84302441 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 3e683919d309..0b1f7f0d1a75 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..93bc9ddfc82c 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 @@ -1,137 +1,149 @@ - - + + + + + + 2026-03-12T19:45:23.036592 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - - - +" transform="scale(0.015625)"/> + + + + + + + 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 01383b77bb40..ebd9008486cc 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 9fd78d2cc24f..fba4d39d586c 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..175cf369c814 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 @@ -1,123 +1,134 @@ - - + + + + + + 2026-03-12T19:45:23.082876 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - - - - - +" transform="scale(0.015625)"/> + + + + + 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 6e3125ca3ec1..5f4fcd094c71 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 2f86fd8bd446..155d80703112 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..6c7d4d4f5cdf 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 @@ -1,212 +1,223 @@ - - + + + + + + 2026-03-12T18:23:41.459535 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - + - + - - - - - - - - - - + + + + + + + + + + + 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 d315d5dc0225..462ad902cd12 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 fb4a9f22fcf8..f26d05780abe 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..776b406aae0f 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 @@ -1,212 +1,223 @@ - - + + + + + + 2026-03-12T19:45:23.176250 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - + - + - - - - - - - - - - + + + + + + + + + + + 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 d160aeb8a343..d03f9e04ffc6 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 5d8e548eff6a..cf07e9179019 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..38f91cd3eeee 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 @@ -1,135 +1,146 @@ - - + + + + + + 2026-03-12T19:45:23.239662 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - - - - - - - - + + + + + + + + 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 306b53a8b953..e75b647fcfb6 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 0415b9e42e10..5305fbd10a69 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..c4c58bb84128 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 @@ -1,238 +1,248 @@ - - + + + + + + 2026-03-12T18:23:41.886317 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - + - - - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - 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 306b53a8b953..916cc5f09f53 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 0415b9e42e10..6735b68a5a8f 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..66821b13cf30 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 @@ -1,238 +1,248 @@ - - + + + + + + 2026-03-12T18:23:41.945224 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - + - + - - - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - 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 38351e4c75db..5f918705bf01 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 67c129bd0fc9..8db55da27ad6 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..46dce0707cf8 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 @@ -1,153 +1,166 @@ - - + + + + + + 2026-03-12T19:45:23.444623 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - + - + - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + 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 3728aee36db3..02070b8ec4a0 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 a512c1bc3b13..10308957630b 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..2c0b48ce2e07 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 @@ -1,248 +1,262 @@ - - + + + + + + 2026-03-12T18:23:42.033336 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 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 f3e67f8d63de..43905663d7a8 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 39fdc0129de8..22fcc24722a7 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..0cb70754432b 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 @@ -1,136 +1,148 @@ - - + + + + + + 2026-03-12T19:45:23.566880 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 c62394e6928a..ec99dbe0c3ec 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 8244bcc0ef68..eb891d989c92 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..48502bf1de01 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 @@ - - + + + + + + 2026-03-12T18:23:42.140170 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - + - - - + - + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - +" 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 afce4eb61520..045289c7f596 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 9274880f3379..6d6544a80145 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..cfdafd0b8717 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 @@ -1,246 +1,250 @@ - - + + + + + + 2026-03-01T22:41:06.590899 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - + - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - 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 44b2f7c77b8c..45a850ff02fb 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 5a9e506e2001..454ac22bd339 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..242772513754 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 @@ -1,364 +1,388 @@ - - + + + + + + 2026-03-12T18:23:42.245899 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - + + + - - - + - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 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 8286912302b1..1213804938fa 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 3d0c67f7c735..3c99312a771f 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..193edec2a89c 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 @@ -1,102 +1,113 @@ - - + + + + + + 2026-03-12T19:45:23.859380 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 96f6dc09e677..192e246be647 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 a8bbd2a8da9b..558d122f004b 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..7a2a9a61a3b1 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 @@ -1,215 +1,228 @@ - - + + + + + + 2026-03-12T18:23:42.376058 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - + - + - - - - - - - - - - + + + + + + + + + + + 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 dfe6b56c97c5..3bf12a624528 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 c1b46fae0ca4..5a9aa25e9770 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..c2fad12feb9d 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 @@ -1,203 +1,216 @@ - - + + + + + + 2026-03-12T18:23:42.429469 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - + - - - - - - - - - +M 2176 653 +L 2176 2125 +Q 2176 2381 1981 2573 +Q 1786 2765 1523 2765 +Q 1158 2765 940 2438 +Q 723 2112 723 1568 +Q 723 979 963 624 +Q 1203 269 1606 269 +Q 1907 269 2080 474 +Q 2176 582 2176 653 +z +" transform="scale(0.015625)"/> + + + + + + + + + + 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 3ec3b1afee95..5cd73a9a61eb 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 a30f7347f874..78ff6ae06fc9 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..5b063bdc006e 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 @@ -1,136 +1,148 @@ - - + + + + + + 2026-03-12T19:45:24.037352 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 d27d1e32215d..187fb68921d5 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 7a9b5f05ace6..c391516530f5 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..b3e205134e38 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 @@ -1,136 +1,148 @@ - - + + + + + + 2026-03-12T19:45:24.097363 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 2600b34ac369..d03a240ed67c 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 a8ef697a36f2..b979f2c53d08 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..3a9c7cc7cdc0 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 @@ -1,277 +1,291 @@ - - + + + + + + 2026-03-12T18:23:42.554686 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - + + - - - + - - + - - - - - - - - - - - - +M 2317 2272 +L 2317 2522 +Q 2317 4147 1472 4147 +Q 1171 4147 1005 3930 +Q 909 3802 845 3546 +Q 781 3290 781 3034 +Q 781 2464 995 2128 +Q 1210 1792 1568 1792 +Q 1824 1792 2070 1917 +Q 2317 2042 2317 2272 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + 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 ccc22a2caced..1001facc2c23 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 b89294879aa4..e11672733939 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..d4f30b0b8ceb 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 @@ -1,275 +1,292 @@ - - + + + + + + 2026-03-12T18:23:42.596089 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - + - - - - - - - - - - - - +M 2278 2310 +Q 2278 2477 2185 2576 +Q 2093 2675 1978 2675 +Q 1677 2675 1395 2381 +Q 1075 2042 864 1571 +Q 653 1101 653 704 +Q 653 486 752 361 +Q 851 237 1024 237 +Q 1312 237 1606 550 +Q 1901 864 2089 1350 +Q 2278 1837 2278 2310 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + 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 3f2e329afa2c..64c2b71b4fdb 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 3a5f0c196252..215410b1b3a3 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..1256f2672d78 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 @@ -1,108 +1,120 @@ - - + + + + + + 2026-03-12T18:23:42.663003 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + 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 58451c13870e..e417754764a2 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 7c66aef99f28..6f62478497c4 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..b14b39809c35 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 @@ -1,130 +1,145 @@ - - + + + + + + 2026-03-12T19:45:24.339027 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + 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 b66f0f9a8ee5..a7a9dbba27f9 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 600c8b66da09..b9ed12718e35 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..f3346e88b4d5 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 @@ -1,159 +1,173 @@ - - + + + + + + 2026-03-12T19:45:24.401897 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + + - + - - - - + - - - - - - - - +M 4077 768 +L 307 768 +L 307 1190 +L 4077 1190 +L 4077 768 +z +" transform="scale(0.015625)"/> + + + + + + + + + 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 d4674f162199..5871f9352d38 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 b8bf22edeb26..f523c3d942aa 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..f937953de551 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 @@ -1,135 +1,151 @@ - - + + + + + + 2026-03-12T19:45:24.446599 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - - +M 1856 288 +Q 1856 147 1760 48 +Q 1664 -51 1523 -51 +Q 1363 -51 1270 48 +Q 1178 147 1178 288 +Q 1178 435 1277 531 +Q 1376 627 1523 627 +Q 1658 627 1757 524 +Q 1856 422 1856 288 +z +" transform="scale(0.015625)"/> + + + + + + 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 da794b5b7bda..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 ab1fdf9f18d3..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 3bdfd4267c70..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 6566d15c5a61..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..294328f978ba 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..a9782477683a 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..6e4695f524d9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_68.svg @@ -0,0 +1,183 @@ + + + + + + + + 2026-03-12T19:45:24.498682 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..34f811bf96e4 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..42bd01c7c2cc 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..ceb428e640c6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_69.svg @@ -0,0 +1,141 @@ + + + + + + + + 2026-03-12T19:45:24.602217 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..39f610484434 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..7d4edd6f0bda 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..451b826b693e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_70.svg @@ -0,0 +1,86 @@ + + + + + + + + 2026-03-12T19:45:24.654626 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..97b62612d0b1 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..679505e06d29 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..d289462d1972 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_71.svg @@ -0,0 +1,173 @@ + + + + + + + + 2026-03-12T19:45:24.730087 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..6ecea8daa0d7 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..2c8eefa4111f 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..6667ca9ace0a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_72.svg @@ -0,0 +1,159 @@ + + + + + + + + 2026-03-12T19:45:24.815240 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..64ee43157f00 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..b9982f0a87b8 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..c3cba9c92216 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_73.svg @@ -0,0 +1,539 @@ + + + + + + + + 2026-03-12T18:23:42.951390 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..64ee43157f00 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..b9982f0a87b8 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..dec8fdcc2cd2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_74.svg @@ -0,0 +1,539 @@ + + + + + + + + 2026-03-12T18:23:43.012637 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..79b916240f26 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..600ef59b66ca 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..0029bfb91dc7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_75.svg @@ -0,0 +1,247 @@ + + + + + + + + 2026-03-12T18:23:43.092010 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..fd0ab1822db4 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..3c2cc2a253dd 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..c2064054f4af --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_76.svg @@ -0,0 +1,263 @@ + + + + + + + + 2026-03-12T19:45:25.144913 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c0e1758edd0c 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..d1469fc48e20 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..f5fd92b5a651 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_78.svg @@ -0,0 +1,208 @@ + + + + + + + + 2026-03-12T18:23:43.220253 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..2e7ac6e51ce6 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..a08f018e61a8 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..e3dde6c72007 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_79.svg @@ -0,0 +1,218 @@ + + + + + + + + 2026-03-12T18:23:43.282056 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..f3138b2d17b9 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..d016fde59c2c 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..1b71e9af4503 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_80.svg @@ -0,0 +1,430 @@ + + + + + + + + 2026-03-12T19:45:25.304495 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c129682c5141 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..c8d90f9d36c0 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..d2112ab3f5a9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_81.svg @@ -0,0 +1,177 @@ + + + + + + + + 2026-03-12T18:23:43.482860 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..a2d7c8931c41 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..089a9571284f 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..4234944a8735 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_82.svg @@ -0,0 +1,189 @@ + + + + + + + + 2026-03-12T18:23:43.521391 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..57fcd2ed5594 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..587c7cde42f0 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..11e68cbdf0f5 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.svg @@ -0,0 +1,159 @@ + + + + + + + + 2026-03-12T19:45:25.522816 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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 8faf4a1222c7..2bd2f060b347 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 45209b207b35..487f438e81c1 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..6e66767aca4e 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 @@ -1,170 +1,187 @@ - - + + + + + + 2026-03-12T19:45:25.597882 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - + - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + 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 770bfbae1a01..759cfa21c210 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 0d2388975c34..46d9cede4073 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..534ddda83ccf 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 @@ -1,128 +1,99 @@ - - + + + + + + 2026-03-12T19:45:25.671429 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - + - - - - - - - - +M 4077 768 +L 307 768 +L 307 1190 +L 4077 1190 +L 4077 768 +z +" transform="scale(0.015625)"/> + + + + + 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 5b7987c9a618..30e3ae87c67e 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 bd27dcb16e2b..c48c6f398ecf 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..c7f2c9ff8f78 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 @@ -1,155 +1,170 @@ - - + + + + + + 2026-03-12T19:45:25.716660 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" 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)"/> + + + + + + + + + + + + + + + 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 409d3ee2b880..414ec5ac99f9 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 ce2510adcf08..8fd32bf9d27a 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..3efdfee0b543 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 @@ -1,150 +1,165 @@ - - + + + + + + 2026-03-12T18:23:43.678850 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - + + - - - - - - - - - - - - + + + + + + + + + + + + + + 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 ec42ffb27c76..6014e23a897c 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 1456df6f2ca0..214c971be650 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..4309e628176c 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 @@ -1,65 +1,75 @@ - - + + + + + + 2026-03-12T19:45:25.839496 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - +" transform="scale(0.015625)"/> + + + 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 8c6188a27067..7aeb4214022c 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 d430d6c1b305..28cb908216f5 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..c089e2d9786c 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 @@ - - + + + + + + 2026-03-12T19:45:25.898393 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + + - + - + - - - - + - - - - - - - - - - - - - - - - - - - - - +" 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 d174e18d71a4..fb15877a8da8 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 a2a9d31e03d0..5d79f180df99 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..eb688642bb80 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 @@ -1,271 +1,290 @@ - - + + + + + + 2026-03-12T19:45:25.990172 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - + - - - - - - - - - - - - - - - - - - +M 3974 4518 +L 1222 -115 +L 922 -115 +L 3443 4096 +Q 3264 3891 3094 3811 +Q 2925 3731 2669 3731 +Q 2445 3731 2182 3821 +Q 2208 3674 2208 3539 +Q 2208 3206 2067 2873 +Q 1926 2541 1696 2323 +Q 1453 2086 1146 2086 +Q 826 2086 608 2339 +Q 390 2592 390 2963 +Q 390 3507 761 3916 +Q 1133 4326 1626 4326 +Q 1792 4326 2010 4147 +Q 2310 3898 2624 3898 +Q 2918 3898 3084 3994 +Q 3251 4090 3693 4518 +L 3974 4518 +z +M 2054 3642 +Q 2054 3782 2025 3833 +Q 1997 3885 1894 3936 +Q 1747 4006 1613 4154 +Q 1414 4058 1331 3984 +Q 1248 3910 1152 3750 +Q 845 3264 845 2707 +Q 845 2509 944 2384 +Q 1043 2259 1210 2259 +Q 1549 2259 1801 2675 +Q 2054 3091 2054 3642 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + 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 d8a7ee0b8386..7954277ea188 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 dfb84f0c6507..38bc28e4d057 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..c505510a70ae 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 @@ -1,113 +1,123 @@ - - + + + + + + 2026-03-12T19:45:26.074445 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + + - - + - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + 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 61f86d6e45d1..a59a823e6079 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 288cadae7c53..382fa0be0fe1 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..e24febb4fff8 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 @@ -1,127 +1,138 @@ - - + + + + + + 2026-03-12T19:45:26.148544 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - + - + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + 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 b2750bec1e00..74d8efdec6a6 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 bfcd82429e29..f850abeea68a 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..4d23bdb99951 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 @@ -1,71 +1,81 @@ - - + + + + + + 2026-03-12T19:45:26.217568 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + 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 c51d2d8bda25..da9b2d841239 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 0497af663f66..9f013133fe3d 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..1729ce067373 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 @@ -1,218 +1,236 @@ - - + + + + + + 2026-03-12T19:45:26.288634 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + 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 70adc66349e5..9c1f2d348b43 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 4195ae2b762b..3dbf8189ada1 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..e4de5a9951a0 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 @@ -1,203 +1,215 @@ - - + + + + + + 2026-03-01T22:41:06.620876 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - + + - + - - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - 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 beda4a4c73e3..fda2a560a4af 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 7f8e356874bf..dc86cee5e566 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..e72967ae0dd7 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 @@ -1,68 +1,80 @@ - - + + + + + + 2026-03-12T19:45:26.422496 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 1e3f3f7f8a24..84476e3c0023 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 d83a0b37143f..afaa49c287cc 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..e1cdec457929 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 @@ -1,134 +1,146 @@ - - + + + + + + 2026-03-12T19:45:26.485202 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - + - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + 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 da043f5cf54f..4755f6edb6fe 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 0d1a101ac9f5..9eeca0342eb6 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..c450b9777f33 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 @@ -1,70 +1,80 @@ - - + + + + + + 2026-03-12T19:45:26.541691 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - +" transform="scale(0.015625)"/> + + + 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 c2c4bc0ccd16..863cecb9d06e 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 5ea1fc8e7641..776749440fb0 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..bdedea33ad01 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 @@ -1,70 +1,80 @@ - - + + + + + + 2026-03-12T19:45:26.583109 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - +" transform="scale(0.015625)"/> + + + 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 9c82b2da0ef6..a3fa5505bc3f 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 7e8f7dfa1c97..5bd4c48bbcb9 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..edf5d6f6075e 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 @@ -1,91 +1,101 @@ - - + + + + + + 2026-03-12T18:23:42.299455 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - - - +" transform="scale(0.015625)"/> + + + + 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 9742897895f1..a3fa5505bc3f 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 7e8f7dfa1c97..5bd4c48bbcb9 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..06a7122110aa 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 @@ -1,91 +1,101 @@ - - + + + + + + 2026-03-12T18:23:42.340873 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - - - +" transform="scale(0.015625)"/> + + + + 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 04e9f589f9b1..39f6ee1c87ad 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 f9864e50573c..ffbc23fee2c1 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..a3fe61d243e4 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 @@ - - + + + + + + 2026-03-12T18:23:42.393791 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 47cc2fe2fd48..e39e3137a4ce 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 5da8088f1a8a..cac9acaad5b3 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..d45e31164454 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 @@ -1,230 +1,241 @@ - - + + + + + + 2026-03-01T22:41:06.944275 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + + - - + - + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - 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 0f66dfe214ca..09e7d27d345d 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 ed82ca80dbd2..fec7a1a13ca9 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..47b5fc2cdcae 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 @@ -1,374 +1,389 @@ - - + + + + + + 2026-03-12T19:45:26.773809 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - + + - + - - + - + + - + - + - - - + - - + - + - + - - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + 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 02269ad7bfb1..c759a6f31ae3 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 bf1d949bc88c..8613e7e92f8a 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..b87e07559b50 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 @@ -1,473 +1,491 @@ - - + + + + + + 2026-03-12T18:23:42.551224 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 5b613f0a2ac3..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 c9558363841c..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 4514c685e0e6..5a23a3ebbaa2 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 be8a9bdce68e..abd30a77ab1c 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..a563a936321c 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 @@ -1,295 +1,314 @@ - - + + + + + + 2026-03-12T19:45:26.917019 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - + - + - + - + - - - + - + - - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + 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 a9670330c4d2..7268a0f8acfb 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 0e0cdee921e4..0e6a81ebd162 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..1834e81cb9cf 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 @@ -1,77 +1,87 @@ - - + + + + + + 2026-03-12T18:23:42.625698 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - - - +" transform="scale(0.015625)"/> + + + + 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 cb116689b0a2..22e8b4fd7802 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 207c06d0df33..b72fd43b6ff1 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..5ddad5ed6c84 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 @@ -1,105 +1,115 @@ - - + + + + + + 2026-03-12T18:23:42.658945 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - + - + + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + 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 2984682bfa1f..a8c125906797 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 989876399e58..8a1d6763a5ab 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..83c8d692f106 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 @@ - - + + + + + + 2026-03-12T19:45:27.040748 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - - - - + - - + - - + - - - - - - - - - - - - - - - - - - +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 +" 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 0dc4e5e0bf41..fa4d7379b7a0 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 648946e858ba..2fc718d0625f 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..7ee537083172 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 @@ -1,203 +1,220 @@ - - + + + + + + 2026-03-12T19:45:27.114222 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - + - - - + - + - - - - - - - - - - - - - - - +M 2509 1459 +Q 2509 1946 2249 2227 +Q 1990 2509 1574 2509 +Q 1171 2509 928 2201 +Q 685 1894 685 1459 +Q 685 998 941 694 +Q 1197 390 1594 390 +Q 2022 390 2265 732 +Q 2509 1075 2509 1459 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + 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 6510c197c985..c9fa5a3a1801 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 976a028f4cef..dfaff2afd4ba 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..22319b858a48 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 @@ - - + + + + + + 2026-03-12T18:23:42.764865 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + - 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 873a98ec70d3..f8aff15f72aa 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 09e30f4755d7..039b32fbc70d 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..756d0a103420 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 @@ -1,235 +1,251 @@ - - + + + + + + 2026-03-12T19:45:27.219401 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - + + - - + - - + - - - - - - - - - - - +M 934 1888 +L 934 787 +Q 1184 390 1594 390 +Q 2010 390 2256 697 +Q 2502 1005 2502 1472 +Q 2502 1914 2278 2211 +Q 2054 2509 1670 2509 +Q 1446 2509 1241 2339 +Q 1037 2170 934 1888 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + 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 2a58560e8659..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 2e1118ec0d82..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 31308f04229d..9d3edeb782e2 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 776563cac7ed..71f0c9ad6b10 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..b9ab5a83556d 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 @@ -1,64 +1,167 @@ - - + + + + + + 2026-03-12T19:45:27.281833 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + 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 d891695f27d9..3868bd61a3eb 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 822a30602427..a484206b9b84 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..e6e162076060 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 @@ -1,134 +1,146 @@ - - + + + + + + 2026-03-12T18:23:42.889446 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - - - - - - - - + + + + + + + + + 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 02bc6f801119..642236cc3af0 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 300929d9d0c7..f85869dd658d 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..41224f39746e 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 @@ -1,178 +1,187 @@ - - + + + + + + 2026-03-12T18:23:42.927222 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + + - + - - + - + - + - - - - - - - - - - - + + + + + + + + + + - 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 fde90ae382bc..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 736f22af4850..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 bb83db213f00..1942bc89e859 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 48fdbef378d0..9c3835013a8b 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..e98e9f28fb59 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 @@ -1,130 +1,140 @@ - - + + + + + + 2026-03-01T22:41:07.604070 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + + - - + - - - - - - - - - + + + + + + + + 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 ca5c7a00989b..9367cca46eb8 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 58b863cee622..175de8d80f5f 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..c4fbf50f703a 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 @@ -1,72 +1,80 @@ - - + + + + + + 2026-03-01T22:41:07.647714 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - - - + + + + + - 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 b354098b2170..34c4950d1bcf 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 5c2dc5a3ee7a..a2391e49856a 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..de7aabaffde6 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 @@ - - + + + + + + 2026-03-12T18:23:43.016833 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 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 a3294b60bdf0..a7f439cfac6d 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 03faea36c7ce..0e98109fac5f 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..1009d867730f 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 @@ -1,324 +1,340 @@ - - + + + + + + 2026-03-12T18:23:43.103937 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - + - + - + - - + - - + - + - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + 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 5581c2c26ba1..355637a60cdf 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 254925790cab..8be384cc07d5 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..9e0dc2c4c4a9 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 @@ -1,206 +1,224 @@ - - + + + + + + 2026-03-12T19:45:27.577160 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - + - - - - - + - - - - - - - - - - +M 1389 1933 +L 1056 602 +Q 1254 390 1587 390 +Q 2048 390 2470 793 +Q 2893 1197 2893 1843 +Q 2893 2150 2729 2329 +Q 2566 2509 2253 2509 +Q 2022 2509 1788 2358 +Q 1555 2208 1389 1933 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + 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 419ed96aaf9e..e0910b795d86 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 4c025a72d250..8566368a972b 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..99535294b86f 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 @@ - - + + + + + + 2026-03-12T19:45:27.645488 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - + + - - + - - + - + - - - - - - - - - - - - - +" 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 a0ca7ee5fe7b..ff9ee44e88d6 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 ebd5e1340e43..dcdb945ac863 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..eb5e0be64990 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 @@ - - + + + + + + 2026-03-12T19:45:27.721075 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 a76a5f60c264..e61f9f9bfc07 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 a15ce7fd9623..6dd2f3fa5d52 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..26c8b087e116 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 @@ -1,92 +1,102 @@ - - + + + + + + 2026-03-12T19:45:27.803298 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - - - - +" transform="scale(0.015625)"/> + + + + + 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 2a7fa8eb7fe0..d8d349c57add 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 3027ca0822bc..9739e14e7541 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..ebe6d1f9098e 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 @@ -1,97 +1,108 @@ - - + + + + + + 2026-03-12T19:45:27.870058 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - - - +" transform="scale(0.015625)"/> + + + + + 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 1b4fba6a13ab..d56f4fa43ae7 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 226a1eb9e5d9..bcec7b958bc6 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..b47e5cbe2f26 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 @@ -1,143 +1,152 @@ - - + + + + + + 2026-03-12T18:23:43.411443 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - + - + - + - - - - - - - - - - + + + + + + + + + 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 028a0ad5f4ea..0444f9d2b40c 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 d2e5f91f887c..298a17ff83b5 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..f22001c972bf 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 @@ -1,143 +1,152 @@ - - + + + + + + 2026-03-12T19:45:27.956461 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - + - + - + - - - - - - - - - - + + + + + + + + + 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 048b01614aef..e75fb5a1e095 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 a4458d332ad3..237d4813a850 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..0f49fbcad4a8 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 @@ -1,120 +1,131 @@ - - + + + + + + 2026-03-12T19:45:28.003651 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - - - - - - - - + + + + + + + + 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 acf7c74161fc..d8061e19a5ca 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 3837c22232e2..8d7d6a8edaee 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..60877da99e86 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 @@ -1,228 +1,238 @@ - - + + + + + + 2026-03-12T18:23:43.186929 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - - + - - - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - 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 56a6c250ddff..2233ed77f418 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 3837c22232e2..574ccb590d41 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..9633a1efb73d 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 @@ -1,228 +1,238 @@ - - + + + + + + 2026-03-12T18:23:43.257680 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - - + - - - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - 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 6efe5792d183..f36f0a0430d3 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 faf51e341556..67a80bb2b0b5 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..232b83438cee 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 @@ -1,123 +1,135 @@ - - + + + + + + 2026-03-12T19:45:28.177840 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - + - + - + - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + 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 930e0306f278..3f1ddbac1321 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 158725100492..697294fd5479 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..31472bda1ba2 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 @@ -1,185 +1,196 @@ - - + + + + + + 2026-03-12T18:23:43.352951 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - + - - + - + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - 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 46c29150dff9..fc31a4ef8f8d 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 1f125ae71d9e..056a2e4b32cc 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..441de291f4db 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 @@ -1,91 +1,101 @@ - - + + + + + + 2026-03-12T19:45:28.291401 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - - - +" transform="scale(0.015625)"/> + + + + 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 f43d685e420f..2fab600677c8 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 1502d6f5f112..6e861939721b 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..960aa9688de4 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 @@ - - + + + + + + 2026-03-12T18:23:43.441037 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - + - - + + - - - - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - +" 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 b309393bf782..4508f45244f1 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 164b3e47acd0..7d734de0cc7e 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..35459fcae3ef 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 @@ -1,208 +1,211 @@ - - + + + + + + 2026-03-01T22:41:07.808510 + image/svg+xml + + + Matplotlib v3.11.0.dev1920+g7b52e93248, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - 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 d5eb1c94679b..a17e4856c4d2 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 16bd6959ed27..2f5c25f7f49d 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..faadba38438f 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 @@ -1,304 +1,324 @@ - - + + + + + + 2026-03-12T18:23:43.549562 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - + + + - - + - + - - + - + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 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 5a57763c9d22..541fe38a3c35 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 f130d361d693..4f2ab0b86bd1 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..0e2894ec3eeb 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 @@ -1,72 +1,82 @@ - - + + + + + + 2026-03-12T19:45:28.560693 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - - - +" transform="scale(0.015625)"/> + + + + + 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 7ab756e0917a..b2694189770e 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 c4f99fcc0890..c48e33a97ddc 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..e254dba365b5 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 @@ -1,172 +1,184 @@ - - + + + + + + 2026-03-12T18:23:43.643888 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - + - - + - - - - - - - - - + + + + + + + + + + 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 bb3693e023eb..ff3d75bb108a 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 38470362648a..a8baeb2b4503 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..c3f8419a695b 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 @@ -1,146 +1,159 @@ - - + + + + + + 2026-03-12T18:23:43.682107 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - + + - + - - + - - - - - - - - - +M 2253 1011 +L 2253 2106 +Q 1978 2509 1594 2509 +Q 1242 2509 963 2201 +Q 685 1894 685 1421 +Q 685 1146 781 906 +Q 877 666 1043 544 +Q 1248 390 1517 390 +Q 1741 390 1945 560 +Q 2150 730 2253 1011 +z +" transform="scale(0.015625)"/> + + + + + + + + + + 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 2317dbd03412..b5289226c08a 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 adb45cb6d794..98f9fcc3eb4e 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..49d45efe3b9a 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 @@ -1,91 +1,101 @@ - - + + + + + + 2026-03-12T19:45:28.704217 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - - - +" transform="scale(0.015625)"/> + + + + 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 75925477d892..8e229bf40d2e 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 bd55798817e9..eca1fce253ea 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..c3b922d793cb 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 @@ -1,91 +1,101 @@ - - + + + + + + 2026-03-12T19:45:28.772350 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - - - +" transform="scale(0.015625)"/> + + + + 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 a2fbd147a56e..1c4f0796007e 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 b78b97856568..131e0d4fca3d 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..d09ba470f84c 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 @@ -1,229 +1,241 @@ - - + + + + + + 2026-03-12T18:23:43.803225 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + + - + - - - + - + - - + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + 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 e3c7b846d216..d6c71120e159 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 979b584cdac9..d1db99ce8b88 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..a89a13e13690 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 @@ -1,177 +1,191 @@ - - + + + + + + 2026-03-12T18:23:43.842813 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - + - + - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + 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 bfec38ebb572..04f1eb64e1b8 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 a91aba9788c3..f69264e163df 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..8f768285a175 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 @@ -1,93 +1,104 @@ - - + + + + + + 2026-03-12T18:23:43.895414 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + 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 8d25579e6e7d..bd48a14a6707 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 0cee0de18f06..474da01f3ffa 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..935a41ecd180 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 @@ -1,115 +1,129 @@ - - + + + + + + 2026-03-12T19:45:29.064477 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + - + - + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + 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 aa99e2283989..44a47a31bb21 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 3744f6069915..c0a97458a6b3 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..26db24a3475c 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 @@ -1,144 +1,158 @@ - - + + + + + + 2026-03-12T19:45:29.117449 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - + + + - + - - - - + - - - - - - - - +M 4077 768 +L 307 768 +L 307 1190 +L 4077 1190 +L 4077 768 +z +" transform="scale(0.015625)"/> + + + + + + + + + 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 654876e9da07..5871f9352d38 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 b8bf22edeb26..f523c3d942aa 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..e61651b166bb 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 @@ -1,135 +1,151 @@ - - + + + + + + 2026-03-12T19:45:29.168151 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - + + - - - - - +M 1856 288 +Q 1856 147 1760 48 +Q 1664 -51 1523 -51 +Q 1363 -51 1270 48 +Q 1178 147 1178 288 +Q 1178 435 1277 531 +Q 1376 627 1523 627 +Q 1658 627 1757 524 +Q 1856 422 1856 288 +z +" transform="scale(0.015625)"/> + + + + + + 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 4e72c0fd146a..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 094e8156d66c..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 ac2a9d954bd7..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 ec6947fc770d..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..ed375e9e0768 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..6a82a8af2071 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..58dab99008d7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_68.svg @@ -0,0 +1,167 @@ + + + + + + + + 2026-03-12T19:45:29.220622 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..2b40f8d2b940 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..e35fc3d59238 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..719d3f11d4a3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_69.svg @@ -0,0 +1,128 @@ + + + + + + + + 2026-03-12T19:45:29.303826 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..2d130284c654 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..81e74ad66367 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..0867f9b08b0b --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_70.svg @@ -0,0 +1,67 @@ + + + + + + + + 2026-03-12T19:45:29.350373 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..97b62612d0b1 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..679505e06d29 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..c9c52509924e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_71.svg @@ -0,0 +1,173 @@ + + + + + + + + 2026-03-12T19:45:29.415822 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..6ecea8daa0d7 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..2c8eefa4111f 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..1d89e506a872 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_72.svg @@ -0,0 +1,159 @@ + + + + + + + + 2026-03-12T19:45:29.841013 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..088ab957c8e6 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..5122e9e77185 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..6336fd6933f1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_73.svg @@ -0,0 +1,357 @@ + + + + + + + + 2026-03-12T18:23:44.192293 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..088ab957c8e6 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..5122e9e77185 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..34caf38131dc --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_74.svg @@ -0,0 +1,357 @@ + + + + + + + + 2026-03-12T18:23:44.251846 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..f7a7dfc9f887 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..e21644bfd6b8 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..54516f9b375c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_75.svg @@ -0,0 +1,189 @@ + + + + + + + + 2026-03-12T18:23:44.327703 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..b049aa4ed1cf 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..2aeaae088213 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..5e5b0ea07420 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_76.svg @@ -0,0 +1,257 @@ + + + + + + + + 2026-03-12T19:45:30.132128 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..a5fc3d1d76ea 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..a42fb8435a8f 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..b60f44145b4d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_78.svg @@ -0,0 +1,215 @@ + + + + + + + + 2026-03-12T18:23:44.461025 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..2fb7dc3c2b23 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..ddbc891f5ab9 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..43c852219844 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_79.svg @@ -0,0 +1,178 @@ + + + + + + + + 2026-03-12T18:23:44.522860 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..b0f6c88081cb 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..6ff648306e27 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..061044a76ca8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_80.svg @@ -0,0 +1,417 @@ + + + + + + + + 2026-03-12T19:45:30.390532 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..46802c7c6245 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..bc3486d66699 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..6a2399c02376 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_81.svg @@ -0,0 +1,135 @@ + + + + + + + + 2026-03-12T18:23:44.627753 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..9fe4914fc40f 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..474ab1e76dcc 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..a6d5cf7c5640 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_82.svg @@ -0,0 +1,168 @@ + + + + + + + + 2026-03-12T18:23:44.670579 + image/svg+xml + + + Matplotlib v3.11.0.dev2071+g094de868c8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..0ac6cacd7ce8 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..106a5adb8b71 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..0dc90f4241f4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.svg @@ -0,0 +1,136 @@ + + + + + + + + 2026-03-12T19:45:30.851295 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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..8553bf61700c 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..6aba9c0e604e 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..75a3bc8b3f09 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..c5c508d90358 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 456a9f2b325b..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 9c8f9c4003d6..425f2f6fe68d 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 11600dda6ea3..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_patches/clip_to_bbox.svg +++ /dev/null @@ -1,509 +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/patch_edgegapcolor.png b/lib/matplotlib/tests/baseline_images/test_patches/patch_edgegapcolor.png new file mode 100644 index 000000000000..a3738e3f7973 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_patches/patch_edgegapcolor.png differ 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..6a77e85c6202 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 index 8edfb8a0a64b..4d08273968c6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_path/semi_log_with_zero.png 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 8f99a867630b..85a9cbb902c9 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 f901fad483a2..4a736ffd0ba0 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 8d63f7fd0451..1c239cfbb616 100644 --- a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.svg +++ b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.svg @@ -1,14619 +1,9635 @@ - - + + + + + + 2026-03-12T19:46:18.815368 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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 2d9a3fd243d6..8f07a0286e89 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 45cdb836cb79..7c1de45bb001 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 7dafdd6277b1..add8a1c66f0d 100644 --- a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.svg +++ b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.svg @@ -1,494 +1,563 @@ - - + + + + + + 2026-04-02T23:50:08.678879 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+gef9968a6c, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - + + - - - - - - - - + + - + - + - - - - - + + - + - - - - - + + - + - - - - - + + - + - - + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - + + + - + - + - + - - - + + + + + - + - + + + + + + + - + - - - - + + + + + + - + - + + + + + + + - + - - - - + + + + + + - + - + + + + + + + - + - - - - + + + + + + - + - + + + + + + + - + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.pdf b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.pdf index 1a13b9d29c57..004498217ff4 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 c09b34c0886a..d9f0aebd4c4e 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 f52e08777fc7..006b5efdd173 100644 --- a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.svg +++ b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.svg @@ -1,846 +1,793 @@ - - + + + + + + 2026-03-12T19:46:17.436336 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, 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 283f603d6ad8..8b7e7fe34a1c 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 e6121f89292e..464c979dc68d 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 346b759d9c55..0d7f44803a2e 100644 --- a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.svg +++ b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.svg @@ -1,2595 +1,2399 @@ - - + + + + + + 2026-04-03T01:40:11.711543 + image/svg+xml + + + Matplotlib v3.11.0.dev2224+gb5b8511fb.d20260403, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - - - - - - - - - + - + - - - - - - - - + + + + + + + + - - - - - - + - + - - - - - - - + + + + + + + - - - - - - + - + - - - - - - - + + + + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - - - - + + + + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - - - - + + + + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - - - - + + + + + + + - - - - - - - - - + - + - + - - - - + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..49ea1bceae2a 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..ba32054f74b0 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 0678d770b373..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 31efe5506528..73b3641a012b 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..494341cee745 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..e42f92b91e8b 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..fb714f23cfa1 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..ec18e6963fa9 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..3966098fe0ba 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..bd7a2e500af6 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..25ceedf4a320 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..fb9e0e9cfe0e 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..af81ffa2b694 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..a7bae8c8a5a6 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..ab39839478a3 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..1c16520ea2e8 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..b5036e8c6557 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 f05d07768957..a7a5ea635c17 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..84d7d66956e8 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 index efb9689ed394..6f2c9e5b056f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_quiver/quiver_single_test_image.png 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 fce1d38a1e7b..4f091b5ef720 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/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 17559b3ebdc7..1137366d7776 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 c88c317ee396..d0fb8869224f 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 1b950b632089..2cbfe69c2370 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,555 +1,467 @@ - - + + + + + + 2026-04-03T00:06:35.968845 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+gef9968a6c.d20260403, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - - - - - - - - - + - + - + - - - - - + + + + + - - - - - - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - - - - - - + - + - - - - - + + + + + - - - - - - + - + - - - - - + + + + + - - - - - - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - - - - - - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - + + - - - +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 +" transform="scale(0.015625)"/> + + - - - - - - - - - + - + - + - + - - + + - + - - - - - - +" 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 8d7559eda0bd..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 e0e9b8b7d471..0a23345be2f7 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 f978b953df6f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_spines/spines_axes_positions.svg +++ /dev/null @@ -1,835 +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 efa68d083a97..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 6634314e2445..41119648636d 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 1e9b07dbfa98..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_spines/spines_data_positions.svg +++ /dev/null @@ -1,548 +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 22d94cc98f34..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 14e42c88bcdc..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 b20f034d875d..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap_test_image.svg +++ /dev/null @@ -1,4806 +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 91b52f3176f6..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 638c150f5e87..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 ac62e5d537ce..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth_test_image.svg +++ /dev/null @@ -1,2944 +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 6613901e7293..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 cd07292e2b3c..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 80134cd3c9ee..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans_test_image.svg +++ /dev/null @@ -1,4045 +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 e871bd270bf2..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 f635bb901e96..9182b1fa2f6c 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 f3e45ad908c0..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.svg +++ /dev/null @@ -1,1802 +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..2ff5c6b39812 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 bd724d32353c..b8490c7f9973 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 01cc2f613255..e06fbda8785f 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..408e5f2aaa64 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..ec2549e939dc 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_coords.png b/lib/matplotlib/tests/baseline_images/test_text/annotation_negative_coords.png deleted file mode 100644 index f5be853ae2e0..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_text/annotation_negative_coords.png and /dev/null 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..42d88450b580 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 45792bbf7381..131e5e878b43 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 57f6a1d7b37b..631872c9fac2 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..da6c0c93df86 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/complex.eps b/lib/matplotlib/tests/baseline_images/test_text/complex.eps new file mode 100644 index 000000000000..947226f5201c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_text/complex.eps @@ -0,0 +1,864 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: complex.eps +%%Creator: Matplotlib v3.11.0.dev1446+gbcd613644c.d20251003, https://matplotlib.org/ +%%CreationDate: Fri Oct 3 03:14:10 2025 +%%Orientation: portrait +%%BoundingBox: 0 0 432 144 +%%HiResBoundingBox: 0.000000 0.000000 432.000000 144.000000 +%%EndComments +%%BeginProlog +/mpldict 13 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 /DejaVuSans-0 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/A /r /a /b /i /c /colon /space] def +/CharStrings 9 dict dup begin +/.notdef 0 def +/A{1401 0 16 0 1384 1493 sc +700 1294 m +426 551 l +975 551 l +700 1294 l + +586 1493 m +815 1493 l +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +586 1493 l + +ce} _d +/r{842 0 186 0 842 1147 sc +842 948 m +821 960 799 969 774 974 c +750 980 723 983 694 983 c +590 983 510 949 454 881 c +399 814 371 717 371 590 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +410 1014 460 1064 522 1097 c +584 1130 659 1147 748 1147 c +761 1147 775 1146 790 1144 c +805 1143 822 1140 841 1137 c +842 948 l + +ce} _d +/a{1255 0 123 -29 1069 1147 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +ce} _d +/b{1300 0 186 -29 1188 1556 sc +997 559 m +997 694 969 800 913 877 c +858 954 781 993 684 993 c +587 993 510 954 454 877 c +399 800 371 694 371 559 c +371 424 399 317 454 240 c +510 163 587 125 684 125 c +781 125 858 163 913 240 c +969 317 997 424 997 559 c + +371 950 m +410 1017 458 1066 517 1098 c +576 1131 647 1147 729 1147 c +865 1147 975 1093 1060 985 c +1145 877 1188 735 1188 559 c +1188 383 1145 241 1060 133 c +975 25 865 -29 729 -29 c +647 -29 576 -13 517 19 c +458 52 410 101 371 168 c +371 0 l +186 0 l +186 1556 l +371 1556 l +371 950 l + +ce} _d +/i{569 0 193 0 377 1556 sc +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +193 1556 m +377 1556 l +377 1323 l +193 1323 l +193 1556 l + +ce} _d +/c{1126 0 113 -29 999 1147 sc +999 1077 m +999 905 l +947 934 895 955 842 969 c +790 984 737 991 684 991 c +565 991 472 953 406 877 c +340 802 307 696 307 559 c +307 422 340 316 406 240 c +472 165 565 127 684 127 c +737 127 790 134 842 148 c +895 163 947 184 999 213 c +999 43 l +948 19 894 1 839 -11 c +784 -23 726 -29 664 -29 c +495 -29 361 24 262 130 c +163 236 113 379 113 559 c +113 742 163 885 263 990 c +364 1095 501 1147 676 1147 c +733 1147 788 1141 842 1129 c +896 1118 948 1100 999 1077 c + +ce} _d +/colon{690 0 240 0 451 1059 sc +240 254 m +451 254 l +451 0 l +240 0 l +240 254 l + +240 1059 m +451 1059 l +451 805 l +240 805 l +240 1059 l + +ce} _d +/space{651 0 0 0 0 0 sc +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-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /DejaVuSans-1 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/product /uni2210 /summation /integral /uniFEE2 /uni0652 /uniFED7 /uni064E /uni0631] def +/CharStrings 10 dict dup begin +/.notdef 0 def +/product{1550 0 156 -393 1393 1473 sc +156 1473 m +1393 1473 l +1393 -393 l +1153 -393 l +1153 1268 l +395 1268 l +395 -393 l +156 -393 l +156 1473 l + +ce} _d +/uni2210{1550 0 156 -393 1393 1473 sc +156 -393 m +156 1473 l +395 1473 l +395 -188 l +1153 -188 l +1153 1473 l +1393 1473 l +1393 -393 l +156 -393 l + +ce} _d +/summation{1380 0 25 -393 1339 1473 sc +55 1473 m +1313 1473 l +1313 1280 l +354 1280 l +1026 563 l +332 -201 l +1339 -201 l +1339 -393 l +25 -393 l +25 -244 l +750 557 l +55 1296 l +55 1473 l + +ce} _d +/integral{1067 0 117 -435 950 1550 sc +483 1250 m +488 1361 518 1439 572 1483 c +626 1528 678 1550 728 1550 c +779 1550 825 1529 867 1487 c +909 1446 937 1378 950 1285 c +802 1270 l +791 1357 766 1400 728 1400 c +681 1400 654 1342 649 1225 c +584 -135 l +579 -246 549 -324 495 -368 c +441 -413 389 -435 338 -435 c +288 -435 242 -414 200 -372 c +158 -331 130 -263 117 -170 c +265 -155 l +276 -242 301 -285 339 -285 c +386 -285 413 -227 418 -110 c +483 1250 l + +ce} _d +/uniFEE2{1363 0 140 -492 1383 628 sc +610 168 m +691 140 757 126 808 126 c +837 126 859 133 873 148 c +908 186 926 224 926 263 c +926 279 924 294 920 307 c +906 366 879 401 840 412 c +813 420 785 424 754 424 c +715 424 686 415 668 397 c +623 352 600 306 600 261 c +600 234 603 203 610 168 c + +1048 52 m +1038 43 1029 35 1020 30 c +931 -23 862 -50 812 -50 c +691 -50 584 -24 490 28 c +457 47 415 30 365 -22 c +348 -39 340 -74 340 -127 c +340 -492 l +140 -492 l +140 -127 l +140 -12 180 80 260 148 c +303 185 355 203 415 203 c +414 231 413 258 413 285 c +413 384 467 477 575 565 c +626 607 683 628 744 628 c +792 628 844 616 900 592 c +1013 545 1083 461 1110 342 c +1120 297 1138 260 1165 231 c +1190 202 1238 187 1308 187 c +1383 187 l +1383 3 l +1253 3 l +1136 3 1068 19 1048 52 c + +ce} _d +/uni0652{0 0 236 1249 784 1798 sc +662 1524 m +662 1566 647 1602 618 1631 c +589 1660 553 1675 510 1675 c +467 1675 430 1660 401 1631 c +372 1602 358 1567 358 1524 c +358 1481 372 1444 401 1415 c +430 1386 467 1372 510 1372 c +553 1372 589 1387 618 1416 c +647 1445 662 1481 662 1524 c + +704 1718 m +757 1665 784 1601 784 1524 c +784 1447 757 1382 704 1329 c +651 1276 587 1249 510 1249 c +433 1249 368 1276 315 1329 c +262 1382 236 1447 236 1524 c +236 1601 262 1665 315 1718 c +368 1771 433 1798 510 1798 c +587 1798 651 1771 704 1718 c + +ce} _d +/uniFED7{979 0 -20 0 831 1300 sc +598 537 m +625 566 639 606 639 657 c +639 696 617 733 573 767 c +552 784 527 792 498 791 c +463 790 433 776 406 748 c +379 721 366 690 365 656 c +365 603 383 563 420 538 c +447 521 474 513 502 513 c +550 513 582 521 598 537 c + +-20 184 m +221 184 l +277 184 355 192 456 207 c +509 215 555 250 595 312 c +616 344 631 377 641 410 c +599 373 546 354 481 353 c +394 352 325 374 273 420 c +208 478 175 550 175 636 c +175 671 178 703 183 732 c +198 831 256 903 356 949 c +408 973 459 985 510 985 c +570 985 622 968 666 935 c +730 887 777 829 808 761 c +823 727 831 663 831 570 c +831 431 805 314 753 219 c +704 128 638 68 555 39 c +482 13 398 0 301 0 c +-20 0 l +-20 184 l + +550 1300 m +700 1300 l +700 1150 l +550 1150 l +550 1300 l + +300 1300 m +450 1300 l +450 1150 l +300 1150 l +300 1300 l + +ce} _d +/uni064E{0 0 220 1210 804 1450 sc +220 1210 m +220 1320 l +804 1450 l +804 1340 l +220 1210 l + +ce} _d +/uni0631{989 0 -85 -500 866 550 sc +675 158 m +682 197 685 240 685 288 c +685 372 667 459 632 550 c +816 550 l +849 471 866 388 866 300 c +866 245 863 197 858 156 c +827 -77 715 -246 521 -349 c +332 -450 130 -500 -85 -500 c +-85 -316 l +118 -316 287 -273 422 -188 c +567 -96 652 19 675 158 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 +%!PS-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /DejaVuSansDisplay-1 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-93 -948 3673 2524] def +/FontType 3 def +/Encoding [/product /uni2210 /summation /integral] def +/CharStrings 5 dict dup begin +/.notdef 0 def +/product{2192 0 221 -556 1970 2083 sc +221 2083 m +1970 2083 l +1970 -556 l +1631 -556 l +1631 1793 l +559 1793 l +559 -556 l +221 -556 l +221 2083 l + +ce} _d +/uni2210{2192 0 221 -556 1970 2083 sc +221 -556 m +221 2083 l +559 2083 l +559 -266 l +1631 -266 l +1631 2083 l +1970 2083 l +1970 -556 l +221 -556 l + +ce} _d +/summation{1951 0 35 -556 1894 2083 sc +78 2083 m +1857 2083 l +1857 1810 l +501 1810 l +1451 796 l +470 -284 l +1894 -284 l +1894 -556 l +35 -556 l +35 -345 l +1061 788 l +78 1833 l +78 2083 l + +ce} _d +/integral{1508 0 165 -615 1344 2192 sc +683 1768 m +691 1925 733 2035 809 2098 c +885 2161 959 2192 1030 2192 c +1101 2192 1167 2163 1226 2104 c +1286 2045 1325 1950 1344 1817 c +1134 1796 l +1118 1919 1083 1980 1030 1980 c +963 1980 926 1897 918 1732 c +826 -191 l +819 -348 777 -458 700 -521 c +623 -584 550 -615 479 -615 c +408 -615 342 -586 282 -527 c +223 -468 184 -373 165 -240 c +375 -219 l +391 -342 426 -403 479 -403 c +546 -403 583 -321 591 -156 c +683 1768 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-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /Cmr10-0 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-90 -512 2066 1536] def +/FontType 3 def +/Encoding [/A /r /a /b /i /c /colon /space] def +/CharStrings 9 dict dup begin +/.notdef 0 def +/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 +/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 +/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 +/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 +/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 +/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 +/space{682 0 0 0 0 0 sc +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 +0 0 translate +0 0 432 144 rectclip +gsave +0 0 m +432 0 l +432 144 l +0 144 l +cl +1 setgray +fill +grestore +0 setgray +/DejaVuSans-1 32.000 selectfont +gsave + +42.1016 96.6875 translate +0 rotate +0 0 m /product glyphshow +24.2188 0 m /uni2210 glyphshow +48.4375 0 m /summation glyphshow +70 0 m /integral glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +42.1016 96.6875 translate +0 rotate +86.6719 0 m /A glyphshow +108.562 0 m /r glyphshow +121.719 0 m /a glyphshow +141.328 0 m /b glyphshow +161.641 0 m /i glyphshow +170.531 0 m /c glyphshow +188.125 0 m /colon glyphshow +198.906 0 m /space glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +42.1016 96.6875 translate +0 rotate +209.078 0 m /uniFEE2 glyphshow +230.188 2.34375 m /uni0652 glyphshow +230.375 0 m /uniFED7 glyphshow +248.609 -7.03125 m /uni064E glyphshow +245.672 0 m /uni0631 glyphshow +261.125 0 m /product glyphshow +285.344 0 m /uni2210 glyphshow +309.562 0 m /summation glyphshow +331.125 0 m /integral glyphshow +grestore +/DejaVuSansDisplay-1 32.000 selectfont +gsave + +11 23.6797 translate +0 rotate +0 0 m /product glyphshow +34.25 0 m /uni2210 glyphshow +68.5 0 m /summation glyphshow +98.9844 0 m /integral glyphshow +grestore +/Cmr10-0 32.000 selectfont +gsave + +11 23.6797 translate +0 rotate +122.547 0 m /A glyphshow +146.547 0 m /r glyphshow +159.062 0 m /a glyphshow +175.062 0 m /b glyphshow +192.828 0 m /i glyphshow +201.688 0 m /c glyphshow +215.891 0 m /colon glyphshow +224.75 0 m /space glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +11 23.6797 translate +0 rotate +235.406 0 m /uniFEE2 glyphshow +256.516 2.34375 m /uni0652 glyphshow +256.703 0 m /uniFED7 glyphshow +274.938 -7.03125 m /uni064E glyphshow +272 0 m /uni0631 glyphshow +grestore +/DejaVuSansDisplay-1 32.000 selectfont +gsave + +11 23.6797 translate +0 rotate +287.453 0 m /product glyphshow +321.703 0 m /uni2210 glyphshow +355.953 0 m /summation glyphshow +386.438 0 m /integral glyphshow +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_text/complex.pdf b/lib/matplotlib/tests/baseline_images/test_text/complex.pdf new file mode 100644 index 000000000000..edc34ea6bc36 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/complex.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/complex.png b/lib/matplotlib/tests/baseline_images/test_text/complex.png new file mode 100644 index 000000000000..63efc96ad8de Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/complex.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/complex.svg b/lib/matplotlib/tests/baseline_images/test_text/complex.svg new file mode 100644 index 000000000000..32496372d2a2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_text/complex.svg @@ -0,0 +1,693 @@ + + + + + + + + 2025-10-03T03:14:10.620956 + image/svg+xml + + + Matplotlib v3.11.0.dev1446+gbcd613644c.d20251003, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_text/draw_text_fallback.png b/lib/matplotlib/tests/baseline_images/test_text/draw_text_fallback.png new file mode 100644 index 000000000000..1de47aff1505 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/draw_text_fallback.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/features.eps b/lib/matplotlib/tests/baseline_images/test_text/features.eps new file mode 100644 index 000000000000..6da3f659a60f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_text/features.eps @@ -0,0 +1,777 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: features.eps +%%Creator: Matplotlib v3.11.0.dev1446+gbcd613644c.d20251003, https://matplotlib.org/ +%%CreationDate: Fri Oct 3 03:14:13 2025 +%%Orientation: portrait +%%BoundingBox: 0 0 360 108 +%%HiResBoundingBox: 0.000000 0.000000 360.000000 108.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 /DejaVuSans-0 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/D /e /f /a /u /l /t /colon /space /s /i /b /d /c /r /o /n /y] def +/CharStrings 19 dict dup begin +/.notdef 0 def +/D{1577 0 201 0 1456 1493 sc +403 1327 m +403 166 l +647 166 l +853 166 1004 213 1099 306 c +1195 399 1243 547 1243 748 c +1243 948 1195 1094 1099 1187 c +1004 1280 853 1327 647 1327 c +403 1327 l + +201 1493 m +616 1493 l +905 1493 1118 1433 1253 1312 c +1388 1192 1456 1004 1456 748 c +1456 491 1388 302 1252 181 c +1116 60 904 0 616 0 c +201 0 l +201 1493 l + +ce} _d +/e{1260 0 113 -29 1151 1147 sc +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +ce} _d +/f{721 0 47 0 760 1556 sc +760 1556 m +760 1403 l +584 1403 l +518 1403 472 1390 446 1363 c +421 1336 408 1288 408 1219 c +408 1120 l +711 1120 l +711 977 l +408 977 l +408 0 l +223 0 l +223 977 l +47 977 l +47 1120 l +223 1120 l +223 1198 l +223 1323 252 1413 310 1470 c +368 1527 460 1556 586 1556 c +760 1556 l + +ce} _d +/a{1255 0 123 -29 1069 1147 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +ce} _d +/u{1298 0 174 -29 1112 1147 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +ce} _d +/l{569 0 193 0 377 1556 sc +193 1556 m +377 1556 l +377 0 l +193 0 l +193 1556 l + +ce} _d +/t{803 0 55 0 754 1438 sc +375 1438 m +375 1120 l +754 1120 l +754 977 l +375 977 l +375 369 l +375 278 387 219 412 193 c +437 167 488 154 565 154 c +754 154 l +754 0 l +565 0 l +423 0 325 26 271 79 c +217 132 190 229 190 369 c +190 977 l +55 977 l +55 1120 l +190 1120 l +190 1438 l +375 1438 l + +ce} _d +/colon{690 0 240 0 451 1059 sc +240 254 m +451 254 l +451 0 l +240 0 l +240 254 l + +240 1059 m +451 1059 l +451 805 l +240 805 l +240 1059 l + +ce} _d +/space{651 0 0 0 0 0 sc +ce} _d +/s{1067 0 111 -29 967 1147 sc +907 1087 m +907 913 l +855 940 801 960 745 973 c +689 986 631 993 571 993 c +480 993 411 979 365 951 c +320 923 297 881 297 825 c +297 782 313 749 346 724 c +379 700 444 677 543 655 c +606 641 l +737 613 829 573 884 522 c +939 471 967 400 967 309 c +967 205 926 123 843 62 c +761 1 648 -29 504 -29 c +444 -29 381 -23 316 -11 c +251 0 183 18 111 41 c +111 231 l +179 196 246 169 312 151 c +378 134 443 125 508 125 c +595 125 661 140 708 169 c +755 199 778 241 778 295 c +778 345 761 383 727 410 c +694 437 620 462 506 487 c +442 502 l +328 526 246 563 195 612 c +144 662 119 730 119 817 c +119 922 156 1004 231 1061 c +306 1118 412 1147 549 1147 c +617 1147 681 1142 741 1132 c +801 1122 856 1107 907 1087 c + +ce} _d +/i{569 0 193 0 377 1556 sc +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +193 1556 m +377 1556 l +377 1323 l +193 1323 l +193 1556 l + +ce} _d +/b{1300 0 186 -29 1188 1556 sc +997 559 m +997 694 969 800 913 877 c +858 954 781 993 684 993 c +587 993 510 954 454 877 c +399 800 371 694 371 559 c +371 424 399 317 454 240 c +510 163 587 125 684 125 c +781 125 858 163 913 240 c +969 317 997 424 997 559 c + +371 950 m +410 1017 458 1066 517 1098 c +576 1131 647 1147 729 1147 c +865 1147 975 1093 1060 985 c +1145 877 1188 735 1188 559 c +1188 383 1145 241 1060 133 c +975 25 865 -29 729 -29 c +647 -29 576 -13 517 19 c +458 52 410 101 371 168 c +371 0 l +186 0 l +186 1556 l +371 1556 l +371 950 l + +ce} _d +/d{1300 0 113 -29 1114 1556 sc +930 950 m +930 1556 l +1114 1556 l +1114 0 l +930 0 l +930 168 l +891 101 842 52 783 19 c +724 -13 654 -29 571 -29 c +436 -29 325 25 240 133 c +155 241 113 383 113 559 c +113 735 155 877 240 985 c +325 1093 436 1147 571 1147 c +654 1147 724 1131 783 1098 c +842 1066 891 1017 930 950 c + +303 559 m +303 424 331 317 386 240 c +442 163 519 125 616 125 c +713 125 790 163 846 240 c +902 317 930 424 930 559 c +930 694 902 800 846 877 c +790 954 713 993 616 993 c +519 993 442 954 386 877 c +331 800 303 694 303 559 c + +ce} _d +/c{1126 0 113 -29 999 1147 sc +999 1077 m +999 905 l +947 934 895 955 842 969 c +790 984 737 991 684 991 c +565 991 472 953 406 877 c +340 802 307 696 307 559 c +307 422 340 316 406 240 c +472 165 565 127 684 127 c +737 127 790 134 842 148 c +895 163 947 184 999 213 c +999 43 l +948 19 894 1 839 -11 c +784 -23 726 -29 664 -29 c +495 -29 361 24 262 130 c +163 236 113 379 113 559 c +113 742 163 885 263 990 c +364 1095 501 1147 676 1147 c +733 1147 788 1141 842 1129 c +896 1118 948 1100 999 1077 c + +ce} _d +/r{842 0 186 0 842 1147 sc +842 948 m +821 960 799 969 774 974 c +750 980 723 983 694 983 c +590 983 510 949 454 881 c +399 814 371 717 371 590 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +410 1014 460 1064 522 1097 c +584 1130 659 1147 748 1147 c +761 1147 775 1146 790 1144 c +805 1143 822 1140 841 1137 c +842 948 l + +ce} _d +/o{1253 0 113 -29 1141 1147 sc +627 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 528 127 627 127 c +725 127 803 166 860 243 c +917 320 946 426 946 559 c +946 692 917 797 860 874 c +803 952 725 991 627 991 c + +627 1147 m +787 1147 913 1095 1004 991 c +1095 887 1141 743 1141 559 c +1141 376 1095 232 1004 127 c +913 23 787 -29 627 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c +113 743 158 887 249 991 c +340 1095 466 1147 627 1147 c + +ce} _d +/n{1298 0 186 0 1124 1147 sc +1124 676 m +1124 0 l +940 0 l +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1027 c +1091 948 1124 831 1124 676 c + +ce} _d +/y{1212 0 61 -426 1151 1120 sc +659 -104 m +607 -237 556 -324 507 -365 c +458 -406 392 -426 309 -426 c +162 -426 l +162 -272 l +270 -272 l +321 -272 360 -260 388 -236 c +416 -212 447 -155 481 -66 c +514 18 l +61 1120 l +256 1120 l +606 244 l +956 1120 l +1151 1120 l +659 -104 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-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /DejaVuSans-1 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/fi /uniFB03 /fl /uniFB06] def +/CharStrings 5 dict dup begin +/.notdef 0 def +/fi{1290 0 47 0 1098 1556 sc +1098 1120 m +1098 0 l +913 0 l +913 977 l +408 977 l +408 0 l +223 0 l +223 977 l +47 977 l +47 1120 l +223 1120 l +223 1198 l +223 1320 252 1410 309 1468 c +367 1527 456 1556 575 1556 c +760 1556 l +760 1403 l +584 1403 l +518 1403 472 1390 446 1363 c +421 1336 408 1288 408 1219 c +408 1120 l +1098 1120 l + +913 1554 m +1098 1554 l +1098 1321 l +913 1321 l +913 1554 l + +ce} _d +/uniFB03{1980 0 47 0 1788 1556 sc +760 1556 m +760 1403 l +584 1403 l +518 1403 472 1390 446 1363 c +421 1336 408 1288 408 1219 c +408 1120 l +913 1120 l +913 1198 l +913 1323 942 1413 1000 1470 c +1019 1489 1041 1504 1067 1517 c +1119 1543 1189 1556 1276 1556 c +1450 1556 l +1450 1403 l +1274 1403 l +1208 1403 1162 1390 1136 1363 c +1111 1336 1098 1288 1098 1219 c +1098 1120 l +1788 1120 l +1788 0 l +1603 0 l +1603 977 l +1098 977 l +1098 0 l +913 0 l +913 977 l +408 977 l +408 0 l +223 0 l +223 977 l +47 977 l +47 1120 l +223 1120 l +223 1198 l +223 1323 252 1413 310 1470 c +368 1527 460 1556 586 1556 c +760 1556 l + +1603 1554 m +1788 1554 l +1788 1321 l +1603 1321 l +1603 1554 l + +ce} _d +/fl{1290 0 47 0 1098 1556 sc +586 1556 m +1098 1556 l +1098 0 l +913 0 l +913 1403 l +584 1403 l +518 1403 472 1390 446 1363 c +421 1336 408 1288 408 1219 c +408 1120 l +711 1120 l +711 977 l +408 977 l +408 0 l +223 0 l +223 977 l +47 977 l +47 1120 l +223 1120 l +223 1198 l +223 1323 252 1413 310 1470 c +368 1527 460 1556 586 1556 c + +ce} _d +/uniFB06{1763 0 111 -29 1714 1520 sc +849 1087 m +849 913 l +792 942 739 962 690 973 c +634 986 583 993 536 993 c +458 993 398 979 356 951 c +317 925 297 883 297 825 c +297 782 313 749 346 724 c +379 700 444 677 543 655 c +606 641 l +736 612 829 573 884 522 c +939 471 967 400 967 309 c +967 205 926 123 844 62 c +761 1 648 -29 504 -29 c +440 -29 377 -23 316 -12 c +251 0 183 18 111 41 c +111 231 l +179 196 246 169 312 152 c +378 134 443 125 508 125 c +595 125 661 140 708 170 c +755 199 778 241 778 295 c +778 345 761 383 728 410 c +698 433 624 459 506 487 c +442 502 l +328 526 246 563 195 612 c +144 662 119 730 119 817 c +119 928 153 1009 221 1061 c +296 1118 393 1147 514 1147 c +562 1147 612 1143 663 1136 c +660 1155 658 1175 658 1196 c +658 1286 689 1363 750 1426 c +811 1488 895 1519 1003 1520 c +1096 1520 1176 1488 1241 1424 c +1304 1363 1335 1287 1335 1196 c +1335 1120 l +1714 1120 l +1714 977 l +1335 977 l +1335 369 l +1335 278 1347 219 1372 193 c +1397 167 1448 154 1525 154 c +1714 154 l +1714 0 l +1525 0 l +1383 0 1285 27 1231 80 c +1177 133 1150 229 1150 369 c +1150 977 l +1015 977 l +1015 1120 l +1150 1120 l +1150 1198 l +1150 1241 1134 1277 1102 1306 c +1066 1339 1025 1356 980 1355 c +934 1355 893 1339 857 1306 c +822 1274 805 1237 805 1194 c +805 1153 820 1118 849 1087 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 +0 0 translate +0 0 360 108 rectclip +gsave +0 0 m +360 0 l +360 108 l +0 108 l +cl +1 setgray +fill +grestore +0 setgray +/DejaVuSans-0 32.000 selectfont +gsave + +91.1406 75.6 translate +0 rotate +0 0 m /D glyphshow +24.6406 0 m /e glyphshow +44.3281 0 m /f glyphshow +55.5938 0 m /a glyphshow +75.2031 0 m /u glyphshow +95.4844 0 m /l glyphshow +104.375 0 m /t glyphshow +116.922 0 m /colon glyphshow +127.703 0 m /space glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +91.1406 75.6 translate +0 rotate +137.875 0 m /fi glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +91.1406 75.6 translate +0 rotate +158.031 0 m /space glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +91.1406 75.6 translate +0 rotate +168.203 0 m /uniFB03 glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +91.1406 75.6 translate +0 rotate +199.141 0 m /space glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +91.1406 75.6 translate +0 rotate +209.312 0 m /fl glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +91.1406 75.6 translate +0 rotate +229.469 0 m /space glyphshow +239.641 0 m /s glyphshow +256.312 0 m /t glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +69.0469 43.2 translate +0 rotate +0 0 m /D glyphshow +24.6406 0 m /i glyphshow +33.5312 0 m /s glyphshow +50.2031 0 m /a glyphshow +69.8125 0 m /b glyphshow +90.125 0 m /l glyphshow +99.0156 0 m /e glyphshow +118.703 0 m /d glyphshow +139.016 0 m /colon glyphshow +149.797 0 m /space glyphshow +159.969 0 m /f glyphshow +171.234 0 m /i glyphshow +180.125 0 m /space glyphshow +190.297 0 m /f glyphshow +201.562 0 m /f glyphshow +212.828 0 m /i glyphshow +221.719 0 m /space glyphshow +231.891 0 m /f glyphshow +243.156 0 m /l glyphshow +252.047 0 m /space glyphshow +262.219 0 m /s glyphshow +278.891 0 m /t glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +-2.54688 10.8 translate +0 rotate +0 0 m /D glyphshow +24.6406 0 m /i glyphshow +33.5312 0 m /s glyphshow +50.2031 0 m /c glyphshow +67.7969 0 m /r glyphshow +80.25 0 m /e glyphshow +99.9375 0 m /t glyphshow +112.484 0 m /i glyphshow +121.375 0 m /o glyphshow +140.953 0 m /n glyphshow +161.234 0 m /a glyphshow +180.844 0 m /r glyphshow +194 0 m /y glyphshow +210.609 0 m /colon glyphshow +221.391 0 m /space glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +-2.54688 10.8 translate +0 rotate +231.562 0 m /fi glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +-2.54688 10.8 translate +0 rotate +251.719 0 m /space glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +-2.54688 10.8 translate +0 rotate +261.891 0 m /uniFB03 glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +-2.54688 10.8 translate +0 rotate +292.828 0 m /space glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +-2.54688 10.8 translate +0 rotate +303 0 m /fl glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +-2.54688 10.8 translate +0 rotate +323.156 0 m /space glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +-2.54688 10.8 translate +0 rotate +333.328 0 m /uniFB06 glyphshow +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_text/features.pdf b/lib/matplotlib/tests/baseline_images/test_text/features.pdf new file mode 100644 index 000000000000..3d1e82468060 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/features.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/features.png b/lib/matplotlib/tests/baseline_images/test_text/features.png new file mode 100644 index 000000000000..94ac41d0796f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/features.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/features.svg b/lib/matplotlib/tests/baseline_images/test_text/features.svg new file mode 100644 index 000000000000..41bf69c9a1bf --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_text/features.svg @@ -0,0 +1,620 @@ + + + + + + + + 2025-10-03T03:14:13.857547 + image/svg+xml + + + Matplotlib v3.11.0.dev1446+gbcd613644c.d20251003, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c59c4594960a 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 ea8304b5460a..5110d915a30f 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 4e0f36082321..0cd24a4b4734 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 37fba48c8076..d625ab807f02 100644 --- a/lib/matplotlib/tests/baseline_images/test_text/font_styles.svg +++ b/lib/matplotlib/tests/baseline_images/test_text/font_styles.svg @@ -1,856 +1,887 @@ - - + + + + + + 2026-04-03T00:06:36.978036 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+gef9968a6c.d20260403, 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..27b0221cf603 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/language.eps b/lib/matplotlib/tests/baseline_images/test_text/language.eps new file mode 100644 index 000000000000..ac4dc4625b9f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_text/language.eps @@ -0,0 +1,657 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: language.eps +%%Creator: Matplotlib v3.11.0.dev1446+gbcd613644c.d20251003, https://matplotlib.org/ +%%CreationDate: Fri Oct 3 03:14:14 2025 +%%Orientation: portrait +%%BoundingBox: 0 0 360 216 +%%HiResBoundingBox: 0.000000 0.000000 360.000000 216.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 /DejaVuSans-0 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/D /e /f /a /u /l /t /L /n /g /space /A /B /M /i /x /d] def +/CharStrings 18 dict dup begin +/.notdef 0 def +/D{1577 0 201 0 1456 1493 sc +403 1327 m +403 166 l +647 166 l +853 166 1004 213 1099 306 c +1195 399 1243 547 1243 748 c +1243 948 1195 1094 1099 1187 c +1004 1280 853 1327 647 1327 c +403 1327 l + +201 1493 m +616 1493 l +905 1493 1118 1433 1253 1312 c +1388 1192 1456 1004 1456 748 c +1456 491 1388 302 1252 181 c +1116 60 904 0 616 0 c +201 0 l +201 1493 l + +ce} _d +/e{1260 0 113 -29 1151 1147 sc +1151 606 m +1151 516 l +305 516 l +313 389 351 293 419 226 c +488 160 583 127 705 127 c +776 127 844 136 910 153 c +977 170 1043 196 1108 231 c +1108 57 l +1042 29 974 8 905 -7 c +836 -22 765 -29 694 -29 c +515 -29 374 23 269 127 c +165 231 113 372 113 549 c +113 732 162 878 261 985 c +360 1093 494 1147 662 1147 c +813 1147 932 1098 1019 1001 c +1107 904 1151 773 1151 606 c + +967 660 m +966 761 937 841 882 901 c +827 961 755 991 664 991 c +561 991 479 962 417 904 c +356 846 320 764 311 659 c +967 660 l + +ce} _d +/f{721 0 47 0 760 1556 sc +760 1556 m +760 1403 l +584 1403 l +518 1403 472 1390 446 1363 c +421 1336 408 1288 408 1219 c +408 1120 l +711 1120 l +711 977 l +408 977 l +408 0 l +223 0 l +223 977 l +47 977 l +47 1120 l +223 1120 l +223 1198 l +223 1323 252 1413 310 1470 c +368 1527 460 1556 586 1556 c +760 1556 l + +ce} _d +/a{1255 0 123 -29 1069 1147 sc +702 563 m +553 563 450 546 393 512 c +336 478 307 420 307 338 c +307 273 328 221 371 182 c +414 144 473 125 547 125 c +649 125 731 161 792 233 c +854 306 885 402 885 522 c +885 563 l +702 563 l + +1069 639 m +1069 0 l +885 0 l +885 170 l +843 102 791 52 728 19 c +665 -13 589 -29 498 -29 c +383 -29 292 3 224 67 c +157 132 123 218 123 326 c +123 452 165 547 249 611 c +334 675 460 707 627 707 c +885 707 l +885 725 l +885 810 857 875 801 921 c +746 968 668 991 567 991 c +503 991 441 983 380 968 c +319 953 261 930 205 899 c +205 1069 l +272 1095 338 1114 401 1127 c +464 1140 526 1147 586 1147 c +748 1147 869 1105 949 1021 c +1029 937 1069 810 1069 639 c + +ce} _d +/u{1298 0 174 -29 1112 1147 sc +174 442 m +174 1120 l +358 1120 l +358 449 l +358 343 379 263 420 210 c +461 157 523 131 606 131 c +705 131 784 163 841 226 c +899 289 928 376 928 485 c +928 1120 l +1112 1120 l +1112 0 l +928 0 l +928 172 l +883 104 831 53 772 20 c +713 -13 645 -29 567 -29 c +438 -29 341 11 274 91 c +207 171 174 288 174 442 c + +637 1147 m +637 1147 l + +ce} _d +/l{569 0 193 0 377 1556 sc +193 1556 m +377 1556 l +377 0 l +193 0 l +193 1556 l + +ce} _d +/t{803 0 55 0 754 1438 sc +375 1438 m +375 1120 l +754 1120 l +754 977 l +375 977 l +375 369 l +375 278 387 219 412 193 c +437 167 488 154 565 154 c +754 154 l +754 0 l +565 0 l +423 0 325 26 271 79 c +217 132 190 229 190 369 c +190 977 l +55 977 l +55 1120 l +190 1120 l +190 1438 l +375 1438 l + +ce} _d +/L{1141 0 201 0 1130 1493 sc +201 1493 m +403 1493 l +403 170 l +1130 170 l +1130 0 l +201 0 l +201 1493 l + +ce} _d +/n{1298 0 186 0 1124 1147 sc +1124 676 m +1124 0 l +940 0 l +940 670 l +940 776 919 855 878 908 c +837 961 775 987 692 987 c +593 987 514 955 457 892 c +400 829 371 742 371 633 c +371 0 l +186 0 l +186 1120 l +371 1120 l +371 946 l +415 1013 467 1064 526 1097 c +586 1130 655 1147 733 1147 c +862 1147 959 1107 1025 1027 c +1091 948 1124 831 1124 676 c + +ce} _d +/g{1300 0 113 -426 1114 1147 sc +930 573 m +930 706 902 810 847 883 c +792 956 715 993 616 993 c +517 993 440 956 385 883 c +330 810 303 706 303 573 c +303 440 330 337 385 264 c +440 191 517 154 616 154 c +715 154 792 191 847 264 c +902 337 930 440 930 573 c + +1114 139 m +1114 -52 1072 -193 987 -286 c +902 -379 773 -426 598 -426 c +533 -426 472 -421 415 -411 c +358 -402 302 -387 248 -367 c +248 -188 l +302 -217 355 -239 408 -253 c +461 -267 514 -274 569 -274 c +690 -274 780 -242 840 -179 c +900 -116 930 -21 930 106 c +930 197 l +892 131 843 82 784 49 c +725 16 654 0 571 0 c +434 0 323 52 239 157 c +155 262 113 400 113 573 c +113 746 155 885 239 990 c +323 1095 434 1147 571 1147 c +654 1147 725 1131 784 1098 c +843 1065 892 1016 930 950 c +930 1120 l +1114 1120 l +1114 139 l + +ce} _d +/space{651 0 0 0 0 0 sc +ce} _d +/A{1401 0 16 0 1384 1493 sc +700 1294 m +426 551 l +975 551 l +700 1294 l + +586 1493 m +815 1493 l +1384 0 l +1174 0 l +1038 383 l +365 383 l +229 0 l +16 0 l +586 1493 l + +ce} _d +/B{1405 0 201 0 1260 1493 sc +403 713 m +403 166 l +727 166 l +836 166 916 188 968 233 c +1021 278 1047 347 1047 440 c +1047 533 1021 602 968 646 c +916 691 836 713 727 713 c +403 713 l + +403 1327 m +403 877 l +702 877 l +801 877 874 895 922 932 c +971 969 995 1026 995 1102 c +995 1177 971 1234 922 1271 c +874 1308 801 1327 702 1327 c +403 1327 l + +201 1493 m +717 1493 l +871 1493 990 1461 1073 1397 c +1156 1333 1198 1242 1198 1124 c +1198 1033 1177 960 1134 906 c +1091 852 1029 818 946 805 c +1045 784 1122 739 1177 671 c +1232 604 1260 519 1260 418 c +1260 285 1215 182 1124 109 c +1033 36 904 0 737 0 c +201 0 l +201 1493 l + +ce} _d +/M{1767 0 201 0 1567 1493 sc +201 1493 m +502 1493 l +883 477 l +1266 1493 l +1567 1493 l +1567 0 l +1370 0 l +1370 1311 l +985 287 l +782 287 l +397 1311 l +397 0 l +201 0 l +201 1493 l + +ce} _d +/i{569 0 193 0 377 1556 sc +193 1120 m +377 1120 l +377 0 l +193 0 l +193 1120 l + +193 1556 m +377 1556 l +377 1323 l +193 1323 l +193 1556 l + +ce} _d +/x{1212 0 59 0 1145 1120 sc +1124 1120 m +719 575 l +1145 0 l +928 0 l +602 440 l +276 0 l +59 0 l +494 586 l +96 1120 l +313 1120 l +610 721 l +907 1120 l +1124 1120 l + +ce} _d +/d{1300 0 113 -29 1114 1556 sc +930 950 m +930 1556 l +1114 1556 l +1114 0 l +930 0 l +930 168 l +891 101 842 52 783 19 c +724 -13 654 -29 571 -29 c +436 -29 325 25 240 133 c +155 241 113 383 113 559 c +113 735 155 877 240 985 c +325 1093 436 1147 571 1147 c +654 1147 724 1131 783 1098 c +842 1066 891 1017 930 950 c + +303 559 m +303 424 331 317 386 240 c +442 163 519 125 616 125 c +713 125 790 163 846 240 c +902 317 930 424 930 559 c +930 694 902 800 846 877 c +790 954 713 993 616 993 c +519 993 442 954 386 877 c +331 800 303 694 303 559 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 +%!PS-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /DejaVuSans-1 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/uni0431 /uniF6C5 /Eng /Eng.alt] def +/CharStrings 5 dict dup begin +/.notdef 0 def +/uni0431{1263 0 112 -29 1151 1591 sc +637 1147 m +797 1147 923 1095 1014 991 c +1105 887 1151 743 1151 559 c +1151 376 1105 232 1014 127 c +923 23 797 -29 637 -29 c +476 -29 352 22 263 123 c +174 224 128 370 123 559 c +117 788 l +114 867 112 921 112 948 c +112 1055 131 1147 170 1226 c +231 1349 313 1438 418 1491 c +523 1544 664 1572 840 1573 c +921 1574 980 1580 1016 1591 c +1067 1445 l +1034 1432 1003 1425 973 1424 c +723 1407 l +639 1401 572 1383 521 1354 c +388 1276 316 1186 303 1084 c +296 1028 l +383 1107 496 1147 637 1147 c + +637 991 m +538 991 460 952 403 875 c +346 798 317 693 317 559 c +317 425 345 319 402 242 c +459 165 538 127 637 127 c +735 127 813 166 870 243 c +927 320 956 426 956 559 c +956 692 927 797 870 874 c +813 952 735 991 637 991 c + +ce} _d +/uniF6C5{1253 0 113 -29 1141 1556 sc +626 991 m +528 991 450 952 393 875 c +336 798 307 693 307 559 c +307 425 335 319 392 242 c +449 165 527 127 626 127 c +725 127 803 166 860 243 c +917 320 946 425 946 558 c +946 691 917 797 860 874 c +803 952 725 991 626 991 c + +113 559 m +113 781 178 944 308 1047 c +255 1078 218 1117 196 1164 c +175 1211 164 1251 164 1284 c +164 1367 196 1433 261 1482 c +326 1531 411 1556 516 1556 c +1024 1556 l +1024 1409 l +552 1409 l +427 1409 364 1363 364 1272 c +364 1223 383 1190 422 1173 c +461 1156 530 1147 627 1147 c +785 1147 910 1095 1002 991 c +1095 887 1141 743 1141 560 c +1141 377 1095 233 1003 128 c +912 23 786 -29 626 -29 c +466 -29 340 23 249 127 c +158 232 113 376 113 559 c + +ce} _d +/Eng{1532 0 201 -426 1305 1520 sc +1104 895 m +1104 1180 1002 1323 797 1323 c +678 1323 582 1280 510 1195 c +439 1110 403 994 403 846 c +403 0 l +201 0 l +201 1493 l +403 1493 l +403 1252 l +455 1341 516 1408 586 1453 c +657 1498 743 1520 845 1520 c +996 1520 1111 1467 1188 1360 c +1266 1254 1305 1098 1305 893 c +1305 -20 l +1305 -162 1278 -265 1224 -330 c +1169 -394 1082 -426 961 -426 c +874 -426 l +874 -270 l +923 -270 l +991 -270 1038 -255 1064 -225 c +1091 -195 1104 -127 1104 -20 c +1104 895 l + +ce} _d +/Eng.alt{1532 0 213 -426 1319 1493 sc +213 1493 m +397 1493 l +1135 344 l +1135 1493 l +1319 1493 l +1319 -20 l +1319 -163 1292 -266 1237 -330 c +1183 -394 1096 -426 975 -426 c +721 -426 l +721 -270 l +954 -270 l +1024 -270 1072 -254 1097 -222 c +1122 -189 1135 -115 1135 0 c +397 1149 l +397 0 l +213 0 l +213 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 +0 0 translate +0 0 360 216 rectclip +gsave +0 0 m +360 0 l +360 216 l +0 216 l +cl +1 setgray +fill +grestore +0 setgray +/DejaVuSans-0 32.000 selectfont +gsave + +0 172.8 translate +0 rotate +0 0 m /D glyphshow +24.6406 0 m /e glyphshow +44.3281 0 m /f glyphshow +55.5938 0 m /a glyphshow +75.2031 0 m /u glyphshow +95.4844 0 m /l glyphshow +104.375 0 m /t glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +0 118.8 translate +0 rotate +0 0 m /L glyphshow +17.8281 0 m /a glyphshow +37.4375 0 m /n glyphshow +57.7188 0 m /g glyphshow +78.0312 0 m /space glyphshow +88.2031 0 m /A glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +0 64.8 translate +0 rotate +0 0 m /L glyphshow +17.8281 0 m /a glyphshow +37.4375 0 m /n glyphshow +57.7188 0 m /g glyphshow +78.0312 0 m /space glyphshow +88.2031 0 m /B glyphshow +grestore +/DejaVuSans-0 32.000 selectfont +gsave + +0 10.8 translate +0 rotate +0 0 m /M glyphshow +27.6094 0 m /i glyphshow +36.5 0 m /x glyphshow +54.4531 0 m /e glyphshow +74.1406 0 m /d glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +144 172.8 translate +0 rotate +0 0 m /uni0431 glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +144 118.8 translate +0 rotate +0 0 m /uniF6C5 glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +144 64.8 translate +0 rotate +0 0 m /uni0431 glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +144 10.8 translate +0 rotate +0 0 m /uni0431 glyphshow +19.7344 0 m /uniF6C5 glyphshow +39.3125 0 m /uni0431 glyphshow +59.0469 0 m /uniF6C5 glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +252 172.8 translate +0 rotate +0 0 m /Eng glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +252 118.8 translate +0 rotate +0 0 m /Eng glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +252 64.8 translate +0 rotate +0 0 m /Eng.alt glyphshow +grestore +/DejaVuSans-1 32.000 selectfont +gsave + +252 10.8 translate +0 rotate +0 0 m /Eng glyphshow +23.9375 0 m /Eng.alt glyphshow +47.875 0 m /Eng glyphshow +71.8125 0 m /Eng.alt glyphshow +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_text/language.pdf b/lib/matplotlib/tests/baseline_images/test_text/language.pdf new file mode 100644 index 000000000000..c199c37318e2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/language.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/language.png b/lib/matplotlib/tests/baseline_images/test_text/language.png new file mode 100644 index 000000000000..db0c8a5c7ced Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/language.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/language.svg b/lib/matplotlib/tests/baseline_images/test_text/language.svg new file mode 100644 index 000000000000..4f21febb77f2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_text/language.svg @@ -0,0 +1,580 @@ + + + + + + + + 2025-10-03T03:14:14.008952 + image/svg+xml + + + Matplotlib v3.11.0.dev1446+gbcd613644c.d20251003, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..b78cbef80378 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 fe27f5cdd171..ed35661d9271 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 eaf752bfc06b..9f266fa44c28 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 28338026aee1..135c592ab808 100644 --- a/lib/matplotlib/tests/baseline_images/test_text/multiline.svg +++ b/lib/matplotlib/tests/baseline_images/test_text/multiline.svg @@ -1,518 +1,484 @@ - - + + + + + + 2026-04-03T00:06:37.346401 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+gef9968a6c.d20260403, 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..f58b695daa13 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..a9728f8eb27b 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..b21f9417a4e1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_text/multiline2.svg @@ -0,0 +1,1594 @@ + + + + + + + + 2026-03-12T19:46:19.479065 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_text/rotation_anchor.png b/lib/matplotlib/tests/baseline_images/test_text/rotation_anchor.png new file mode 100644 index 000000000000..04c0cd8baeac Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/rotation_anchor.png differ 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 e6199559b9da..08228c48f644 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 a4f11d9fac9d..26cf20e8ec3e 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 2e1ab2a7c384..5167ed788a4e 100644 --- a/lib/matplotlib/tests/baseline_images/test_text/text_alignment.svg +++ b/lib/matplotlib/tests/baseline_images/test_text/text_alignment.svg @@ -1,858 +1,787 @@ - - + + + + + + 2026-03-12T19:46:22.180713 + image/svg+xml + + + Matplotlib v3.11.0.dev2072+gb1cf5d4866.d20260312, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> + + - + - + - + - + - + - + - - - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - + + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + + - - + + 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 index e097e1e5c8cb..8654643311da 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.pdf 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 index 33c363d52148..4ed8dc5f3a61 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.png 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 index 2b0b2068c8e6..c05061943f23 100644 --- a/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.svg +++ b/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.svg @@ -1,893 +1,846 @@ - - + + + + + + 2026-04-03T00:06:41.548124 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+gef9968a6c.d20260403, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - +" style="fill: #ffffff"/> - + - - - - - - - - - + - - - - - - - - + + + + + + + + - - - - - - + - + - - - - - - - + + + + + + + - - - - - - + - + - - - - - - - + + + + + + + - - - - - - + - + - - - - - - - + + + + + + + - - - - - - + - + - - - - - - - + + + + + + + - - - - - - + - + - - - - - - - + + + + + + + - - - - - - - - - + - + - + - - - - + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - + + + + - - - - - - + - + - - - - + + + + + + + + + + + + + + + + - +" clip-path="url(#pb041380c4d)" style="fill: #ff0000; stroke: #ff0000; stroke-linejoin: miter"/> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + 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 5f5f2e9404db..8736ae10a5a2 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/titles.pdf b/lib/matplotlib/tests/baseline_images/test_text/titles.pdf index eca6a832de22..8b0f977d8a21 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 a830766304ca..b181299caca1 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 b31dffece94f..d76d5429496f 100644 --- a/lib/matplotlib/tests/baseline_images/test_text/titles.svg +++ b/lib/matplotlib/tests/baseline_images/test_text/titles.svg @@ -1,247 +1,255 @@ - - + + + + + + 2026-04-03T00:06:39.913712 + image/svg+xml + + + Matplotlib v3.11.0.dev2221+gef9968a6c.d20260403, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> + + - + - + - + - + - - - - - + + - + - + - + - + + - - - - - - - - - - - - +M 603 4863 +L 1178 4863 +L 1178 4134 +L 603 4134 +L 603 4863 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + - - + + + - + - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + 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..c868837c903d 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..1bb50bc0b373 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 061f35870fa1..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 0195dca14596..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 349e23404416..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,519 +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 9b1584ec3c76..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 7f0bef91e9bc..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 71f0f08cac16..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,1122 +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"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + 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 bd683edaf98f..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 e152395bd730..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 d9875c7a7fc5..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,921 +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"/> - + - + - + - - - - - - - - - - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - - - - + - - - - - - - - - - +"/> - - - - - - - - - + - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - - - - - - - - - - - - + - - - - - + - - - - - - - - - +"/> - - - - - - + - - - - - - - - +"/> - - - - + + - - + + - - + + + + + - - + + - - + + - - + + + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - - - - + + - - - - + + - - + + - - + + - - + + - - + + - - + + + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - - - - + + + + + + + + + + + + + + + + + - - + + - - + + - - + + 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 c782936b11cc..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 8800c270f9fa..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 e238f2ae4d00..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,1122 +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"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + 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 b730c600cc5d..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 6643b0a6bfb9..15b0c247a793 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 5d6d838b39f3..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,405 +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 8b33c78a7461..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 c68654321057..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 0d2a1d69e81a..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,1269 +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"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - + + - - + + - - + + - - + + - - + + - - + + + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - + - + - - - - - - - - - - - - + + - - - - - - - - - - - + + - - - - + + - - + + - - + + - - + + - - + + - - + + + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + 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 22abe998a57f..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 fddf632dc2c7..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 1455bcd695fc..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,651 +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 fe01a511bcad..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 75630dff9038..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 15877e4d9bde..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,519 +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 27c4722fcac9..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 414972144c25..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 117ab1abf587..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,5430 +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 e513ce86b92e..f7ac255e56a6 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_ttconv/truetype-conversion.pdf b/lib/matplotlib/tests/baseline_images/test_ttconv/truetype-conversion.pdf deleted file mode 100644 index db47fad3a51a..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_ttconv/truetype-conversion.pdf and /dev/null 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..1585e43078bf 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..f4f409ebf5d5 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..dacc0d8b4e84 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..df6cbcd103c2 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..3463cc1e774c 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..48838f41e698 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_usetex/rotation.svg @@ -0,0 +1,1387 @@ + + + + + + + + 2025-07-11T18:21:45.436534 + image/svg+xml + + + Matplotlib v3.11.0.dev1079+g8ff030e131, 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..f2ebbeb528cc 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..e4a62a1c87ae 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..65232c461f4e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_widgets/check_radio_buttons.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_widgets/check_radio_grid_buttons.png b/lib/matplotlib/tests/baseline_images/test_widgets/check_radio_grid_buttons.png new file mode 100644 index 000000000000..632b00b17f7f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_widgets/check_radio_grid_buttons.png differ diff --git a/lib/matplotlib/tests/conftest.py b/lib/matplotlib/tests/conftest.py new file mode 100644 index 000000000000..3f38f50ccc7f --- /dev/null +++ b/lib/matplotlib/tests/conftest.py @@ -0,0 +1,3 @@ +from matplotlib.testing.conftest import ( # noqa + pytest_configure, pytest_unconfigure, + high_memory, mpl_test_settings, 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.... + # #

    + #
    + #