├── .devcontainer
└── devcontainer.json
├── .github
├── dependabot.yml
└── workflows
│ ├── build_docs.yaml
│ ├── python-publish.yml
│ └── test.yaml
├── .gitignore
├── .pre-commit-config.yaml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── docs
├── changelog.md
├── images
│ └── zhplot_demo.png
├── index.md
└── overrides
│ └── main.html
├── mkdocs.yml
├── pyproject.toml
├── tests
├── test_matplotlib.py
└── test_wordcloud.py
├── uv.lock
└── zhplot
├── __init__.py
├── fonts
├── NotoSansSC-Regular.ttf
├── OFL.txt
└── README.txt
├── matplotlib.py
├── py.typed
└── wordcloud.py
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2 | // README at: https://github.com/devcontainers/templates/tree/main/src/python
3 | {
4 | "name": "ZhPlot - VS Code dev container",
5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6 | "image": "mcr.microsoft.com/devcontainers/python:1-3.12",
7 |
8 | // Features to add to the dev container. More info: https://containers.dev/features.
9 | "features": {
10 | "ghcr.io/devcontainers-contrib/features/poetry:2": {}
11 | },
12 |
13 | // Configure tool-specific properties.
14 | "customizations": {
15 | // Configure properties specific to VS Code.
16 | "vscode": {
17 | "settings": {},
18 | "extensions": [
19 | "streetsidesoftware.code-spell-checker"
20 | ]
21 | },
22 | "codespaces": {
23 | "openFiles": [
24 | "README.md",
25 | ]
26 | }
27 | },
28 |
29 | // Use 'forwardPorts' to make a list of ports inside the container available locally.
30 | // "forwardPorts": [9000],
31 |
32 | // Use 'portsAttributes' to set default properties for specific forwarded ports.
33 | // More info: https://containers.dev/implementors/json_reference/#port-attributes
34 | // "portsAttributes": {
35 | // "9000": {
36 | // "label": "Hello Remote World",
37 | // "onAutoForward": "notify"
38 | // }
39 | // },
40 |
41 | // Use 'postCreateCommand' to run commands after the container is created.
42 | "postCreateCommand": "poetry install"
43 |
44 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
45 | // "remoteUser": "root"
46 | }
47 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "github-actions"
9 | directory: "/"
10 | schedule:
11 | interval: "daily"
12 | - package-ecosystem: "pip"
13 | directory: "/"
14 | schedule:
15 | interval: "monthly"
16 |
--------------------------------------------------------------------------------
/.github/workflows/build_docs.yaml:
--------------------------------------------------------------------------------
1 | name: Docs
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 |
9 | jobs:
10 | build:
11 | name: Build docs (python-${{ matrix.os }})
12 | strategy:
13 | matrix:
14 | os:
15 | - ubuntu-latest
16 | fail-fast: false
17 | runs-on: ${{ matrix.os }}
18 | env:
19 | UV_HTTP_TIMEOUT: 900 # max 15min to install deps
20 | steps:
21 | - uses: actions/checkout@v4
22 | with:
23 | fetch-depth: 0
24 |
25 | - name: Install uv
26 | uses: astral-sh/setup-uv@v6
27 | with:
28 | enable-cache: true
29 | cache-dependency-glob: "uv.lock"
30 |
31 | - name: "Set up Python"
32 | uses: actions/setup-python@v5
33 | with:
34 | python-version-file: "pyproject.toml"
35 |
36 | - name: Install the project
37 | run: uv sync --extra docs
38 |
39 | - name: Build docs
40 | run: uv run mkdocs build
41 |
42 | - name: Minimize uv cache
43 | run: uv cache prune --ci
44 |
45 | deploy:
46 | name: Deploy docs
47 | needs: build
48 | if: github.event_name == 'push' && github.ref == 'refs/heads/master'
49 | runs-on: ubuntu-latest
50 | env:
51 | UV_HTTP_TIMEOUT: 900 # max 15min to install deps
52 | steps:
53 | - uses: actions/checkout@v4
54 | with:
55 | fetch-depth: 0
56 |
57 | - name: Install uv
58 | uses: astral-sh/setup-uv@v6
59 | with:
60 | enable-cache: true
61 | cache-dependency-glob: "uv.lock"
62 |
63 | - name: "Set up Python"
64 | uses: actions/setup-python@v5
65 | with:
66 | python-version-file: "pyproject.toml"
67 |
68 | - name: Install the project
69 | run: uv sync --extra docs
70 |
71 | - name: Deploy docs
72 | run: uv run mkdocs gh-deploy --force
73 |
74 | - name: Minimize uv cache
75 | run: uv cache prune --ci
76 |
--------------------------------------------------------------------------------
/.github/workflows/python-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will upload a Python Package using Twine when a release is created
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3 |
4 | # This workflow uses actions that are not certified by GitHub.
5 | # They are provided by a third-party and are governed by
6 | # separate terms of service, privacy policy, and support
7 | # documentation.
8 |
9 | name: Upload Python Package
10 |
11 | on:
12 | release:
13 | types: [published]
14 |
15 | permissions:
16 | contents: read
17 |
18 | jobs:
19 | pypi-publish:
20 | name: upload release to PyPI
21 | runs-on: ubuntu-latest
22 | # Specifying a GitHub environment is optional, but strongly encouraged
23 | environment: pypi
24 | permissions:
25 | # IMPORTANT: this permission is mandatory for trusted publishing
26 | id-token: write
27 | steps:
28 | - uses: actions/checkout@v4
29 | - name: Install uv
30 | uses: astral-sh/setup-uv@v6
31 | with:
32 | enable-cache: true
33 | cache-dependency-glob: "uv.lock"
34 | - name: "Set up Python"
35 | uses: actions/setup-python@v5
36 | with:
37 | python-version-file: "pyproject.toml"
38 |
39 | - name: Install the project
40 | run: uv sync --all-extras --dev
41 | - name: Build package
42 | run: uv build
43 | - name: Publish package distributions to PyPI
44 | uses: pypa/gh-action-pypi-publish@release/v1
45 |
--------------------------------------------------------------------------------
/.github/workflows/test.yaml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 |
9 | jobs:
10 | ci:
11 | strategy:
12 | fail-fast: false
13 | matrix:
14 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15 | os: [ubuntu-latest, macos-latest, windows-latest]
16 | exclude:
17 | # TODO: re-include it
18 | # excludes python3.13 on windows due to error: Windows fatal exception: access violation
19 | - os: windows-latest
20 | python-version: "3.13"
21 | runs-on: ${{ matrix.os }}
22 | env:
23 | UV_HTTP_TIMEOUT: 900 # max 15min to install deps
24 | steps:
25 | - uses: actions/checkout@v4
26 |
27 | - name: Install uv
28 | uses: astral-sh/setup-uv@v6
29 | with:
30 | enable-cache: true
31 | cache-dependency-glob: "uv.lock"
32 |
33 | - name: Set up Python
34 | uses: actions/setup-python@v5
35 | with:
36 | python-version: ${{ matrix.python-version }}
37 |
38 | - name: Install the project
39 | run: uv sync --all-extras --dev
40 |
41 | - name: Run tests and generate coverage report
42 | run: uv run pytest --doctest-modules -v --cov=zhplot --cov-fail-under 90 --cov-report=term --cov-report=xml --cov-report=html zhplot tests
43 |
44 | - name: Upload test results to Codecov
45 | if: success() && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
46 | uses: codecov/test-results-action@v1
47 | with:
48 | token: ${{ secrets.CODECOV_TOKEN }}
49 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ide cache
2 | .vscode
3 | .idea
4 |
5 |
6 |
7 | # Byte-compiled / optimized / DLL files
8 | __pycache__/
9 | *.py[cod]
10 | *$py.class
11 |
12 | # C extensions
13 | *.so
14 |
15 | # Distribution / packaging
16 | .Python
17 | build/
18 | develop-eggs/
19 | dist/
20 | downloads/
21 | eggs/
22 | .eggs/
23 | lib/
24 | lib64/
25 | parts/
26 | sdist/
27 | var/
28 | wheels/
29 | share/python-wheels/
30 | *.egg-info/
31 | .installed.cfg
32 | *.egg
33 | MANIFEST
34 |
35 | # PyInstaller
36 | # Usually these files are written by a python script from a template
37 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
38 | *.manifest
39 | *.spec
40 |
41 | # Installer logs
42 | pip-log.txt
43 | pip-delete-this-directory.txt
44 |
45 | # Unit test / coverage reports
46 | htmlcov/
47 | .tox/
48 | .nox/
49 | .coverage
50 | .coverage.*
51 | .cache
52 | nosetests.xml
53 | coverage.xml
54 | *.cover
55 | *.py,cover
56 | .hypothesis/
57 | .pytest_cache/
58 | cover/
59 |
60 | # Translations
61 | *.mo
62 | *.pot
63 |
64 | # Django stuff:
65 | *.log
66 | local_settings.py
67 | db.sqlite3
68 | db.sqlite3-journal
69 |
70 | # Flask stuff:
71 | instance/
72 | .webassets-cache
73 |
74 | # Scrapy stuff:
75 | .scrapy
76 |
77 | # Sphinx documentation
78 | docs/_build/
79 |
80 | # PyBuilder
81 | .pybuilder/
82 | target/
83 |
84 | # Jupyter Notebook
85 | .ipynb_checkpoints
86 |
87 | # IPython
88 | profile_default/
89 | ipython_config.py
90 |
91 | # pyenv
92 | # For a library or package, you might want to ignore these files since the code is
93 | # intended to run in multiple environments; otherwise, check them in:
94 | # .python-version
95 |
96 | # pipenv
97 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
98 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
99 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
100 | # install all needed dependencies.
101 | #Pipfile.lock
102 |
103 | # poetry
104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105 | # This is especially recommended for binary packages to ensure reproducibility, and is more
106 | # commonly ignored for libraries.
107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108 | #poetry.lock
109 |
110 | # pdm
111 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112 | #pdm.lock
113 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
114 | # in version control.
115 | # https://pdm.fming.dev/#use-with-ide
116 | .pdm.toml
117 |
118 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
119 | __pypackages__/
120 |
121 | # Celery stuff
122 | celerybeat-schedule
123 | celerybeat.pid
124 |
125 | # SageMath parsed files
126 | *.sage.py
127 |
128 | # Environments
129 | .env
130 | .venv
131 | env/
132 | venv/
133 | ENV/
134 | env.bak/
135 | venv.bak/
136 |
137 | # Spyder project settings
138 | .spyderproject
139 | .spyproject
140 |
141 | # Rope project settings
142 | .ropeproject
143 |
144 | # mkdocs documentation
145 | /site
146 |
147 | # mypy
148 | .mypy_cache/
149 | .dmypy.json
150 | dmypy.json
151 |
152 | # Pyre type checker
153 | .pyre/
154 |
155 | # pytype static type analyzer
156 | .pytype/
157 |
158 | # Cython debug symbols
159 | cython_debug/
160 |
161 | # PyCharm
162 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
163 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
164 | # and can be added to the global gitignore or merged into this file. For a more nuclear
165 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
166 | #.idea/
167 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pre-commit/pre-commit-hooks
3 | rev: v5.0.0
4 | hooks:
5 | - id: check-toml
6 | - id: check-yaml
7 | - id: end-of-file-fixer
8 | - id: trailing-whitespace
9 | exclude: .+\.csv
10 | - id: mixed-line-ending
11 | args: [--fix=lf]
12 | - repo: https://github.com/pycqa/isort
13 | rev: 6.0.1
14 | hooks:
15 | - id: isort
16 | args: ["--profile", "black", "--filter-files"]
17 | - repo: https://github.com/astral-sh/ruff-pre-commit
18 | # Ruff version.
19 | rev: v0.11.12
20 | hooks:
21 | # Run the linter.
22 | - id: ruff
23 | # Run the formatter.
24 | - id: ruff-format
25 | - repo: https://github.com/pre-commit/mirrors-mypy
26 | rev: v1.16.0 # Use the sha / tag you want to point at
27 | hooks:
28 | - id: mypy
29 | args: ["--install-types", "--non-interactive", "--ignore-missing-imports", "--check-untyped-defs"]
30 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 |
4 | ## [Unreleased]
5 |
6 | ## [1.0.0] - 2024-12-26
7 |
8 | ### Docs
9 | - Add more docs
10 |
11 |
12 | ## [0.2.0] - 2024-12-17
13 |
14 | ### Added
15 | - Support chinese display in `wordcloud`
16 |
17 |
18 | ## [0.1.1] - 2024-12-01
19 |
20 | ### Changed
21 | - Change from `SimHei` to `Noto Sans SC`
22 |
23 |
24 | ## [0.1.0] - 2024-11-30
25 |
26 | ### Added
27 | - Support chinese in `matplotlib`
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Mathew Shen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Zh-Plot: 一行代码搞定 Python 图表中文展示
2 |
3 | [](https://pypi.org/project/zhplot/)
4 | [](https://pypi.org/project/zhplot/)
5 | [](https://pepy.tech/projects/zhplot)
6 |
7 | [](https://github.com/psf/black)
8 | [](https://github.com/astral-sh/ruff)
9 | [](https://pycqa.github.io/isort/)
10 | [](https://mypy-lang.org/)
11 | [](https://github.com/pre-commit/pre-commit)
12 |
13 | [](https://github.com/shenxiangzhuang/zhplot/actions/workflows/build_docs.yaml)
14 | [](https://github.com/shenxiangzhuang/zhplot/actions/workflows/test.yaml)
15 | [](https://codecov.io/gh/shenxiangzhuang/zhplot)
16 | [](https://github.com/shenxiangzhuang/zhplot/blob/master/LICENSE)
17 |
18 |
19 | ## 支持的框架
20 | - [x] [matplotlib](https://github.com/matplotlib/matplotlib)
21 | - [x] [wordcloud](https://github.com/amueller/word_cloud)
22 |
23 |
24 | ## 快速开始
25 |
26 | ### 安装
27 |
28 | 使用 [pip](https://pip.pypa.io/) 安装`zhplot`:
29 |
30 | ```bash
31 | pip install zhplot
32 | ```
33 |
34 | 使用 [uv](https://docs.astral.sh/uv/) 安装`zhplot`:
35 |
36 | ```bash
37 | uv add zhplot
38 | ```
39 |
40 |
41 | ### 使用方法
42 |
43 | 使用`zhplot`非常简单,只需在脚本开头导入即可:
44 | ```diff
45 | + import zhplot
46 | import matplotlib.pyplot as plt
47 | ```
48 |
49 | 在汉化 wordcloud 的时候`import zhplot`需要在前面:
50 | ```diff
51 | + import zhplot
52 | import wordcloud
53 | ```
54 |
55 | ### 一个简单的例子
56 |
57 |

58 |
59 |
60 | ```python
61 | import zhplot
62 | import matplotlib.pyplot as plt
63 |
64 |
65 | plt.plot([1, 2, 3, 4])
66 | plt.title('这是一个标题')
67 | plt.xlabel('横坐标')
68 | plt.ylabel('纵坐标')
69 | plt.show()
70 | ```
71 |
72 |
73 | ## 相似项目
74 | - [japanize-matplotlib](https://github.com/uehara1414/japanize-matplotlib)
75 | - [chineseize-matplotlib](https://github.com/cndeng/chineseize-matplotlib)
76 |
--------------------------------------------------------------------------------
/docs/changelog.md:
--------------------------------------------------------------------------------
1 | --8<-- "CHANGELOG.md"
2 |
--------------------------------------------------------------------------------
/docs/images/zhplot_demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shenxiangzhuang/zhplot/f5d6d788fef310d72022037ad7531fa6a84d4473/docs/images/zhplot_demo.png
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | --8<-- "README.md"
2 |
--------------------------------------------------------------------------------
/docs/overrides/main.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: Zh-Plot
2 | repo_url: https://github.com/shenxiangzhuang/zhplot
3 | repo_name: shenxiangzhuang/zhplot
4 | site_description: Show Chinese in Figures with one line code.
5 | site_author: Xiangzhuang Shen
6 | copyright: Copyright © 2024 Xiangzhuang Shen
7 |
8 | # Page tree
9 | nav:
10 | - Home: index.md
11 | - Changelog: changelog.md
12 | - Author's website: https://shenxiangzhuang.github.io/
13 |
14 | theme:
15 | name: material
16 | custom_dir: docs/overrides
17 | icon:
18 | repo: fontawesome/brands/github
19 | language: en
20 | palette:
21 | - media: "(prefers-color-scheme: light)"
22 | scheme: default
23 | primary: teal
24 | accent: deep purple
25 | toggle:
26 | icon: material/weather-sunny
27 | name: Switch to dark mode
28 | - media: "(prefers-color-scheme: dark)"
29 | scheme: slate
30 | primary: cyan
31 | accent: deep purple
32 | toggle:
33 | icon: material/weather-night
34 | name: Switch to light mode
35 | features:
36 | - content.action.edit
37 | - content.action.view
38 | - announce.dismiss
39 | - content.code.annotate
40 | - content.tabs.link
41 | - content.tooltips
42 | - header.autohide
43 | - navigation.instant
44 | - navigation.tracking
45 | - navigation.tabs
46 | - navigation.tabs.sticky
47 | - navigation.indexes
48 | - navigation.prune
49 | - navigation.sections
50 | - navigation.top
51 | - search.highlight
52 | - search.share
53 | - search.suggest
54 | - toc.follow
55 | # - toc.integrate
56 | - content.code.annotate
57 |
58 | docs_dir: docs
59 |
60 |
61 | extra_javascript:
62 | - js/config.js
63 | - https://polyfill.io/v3/polyfill.min.js?features=es6
64 | - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
65 |
66 | extra:
67 | social:
68 | - icon: fontawesome/brands/github
69 | link: https://github.com/shenxiangzhuang/
70 | - icon: fontawesome/brands/linkedin
71 | link: https://www.linkedin.com/in/xiangzhuang-shen-a81825157/
72 |
73 | markdown_extensions:
74 | - def_list
75 | - pymdownx.tasklist:
76 | custom_checkbox: true
77 | - toc:
78 | permalink: true
79 | - pymdownx.arithmatex:
80 | generic: true
81 | - pymdownx.highlight:
82 | linenums_style: pymdownx.inline
83 | - pymdownx.superfences
84 | - pymdownx.inlinehilite
85 | - pymdownx.details
86 | - pymdownx.snippets:
87 | url_download: true
88 | - pymdownx.tabbed:
89 | alternate_style: true
90 | - abbr
91 | - admonition
92 | - attr_list
93 | - footnotes
94 |
95 | plugins:
96 | - search
97 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools >= 61.0"]
3 | build-backend = "setuptools.build_meta"
4 |
5 |
6 | [project]
7 | name = "zhplot"
8 | version = "1.0.0"
9 | description = " 一行代码搞定Python图表中文展示(Show Chinese in Figures with one line code)"
10 | authors = [
11 | {name = "Xiangzhuang Shen", email = "datahonor@gmail.com"},
12 | ]
13 | license = {text = "MIT"}
14 | readme = "README.md"
15 |
16 |
17 | classifiers=[
18 | "Development Status :: 5 - Production/Stable",
19 | "Intended Audience :: Science/Research",
20 | "Intended Audience :: Developers",
21 | "License :: OSI Approved :: MIT License",
22 | "Operating System :: OS Independent",
23 | "Framework :: Matplotlib",
24 | "Programming Language :: Python :: 3.9",
25 | "Programming Language :: Python :: 3.10",
26 | "Programming Language :: Python :: 3.11",
27 | "Programming Language :: Python :: 3.12",
28 | "Programming Language :: Python :: 3.13",
29 | "Typing :: Typed",
30 | ]
31 | requires-python = ">= 3.9"
32 | dependencies = [
33 | "matplotlib>=3.9.2",
34 | ]
35 |
36 | [project.optional-dependencies]
37 | dev = [
38 | "pre-commit",
39 | "ipython",
40 | "black",
41 | "flake8",
42 | "mypy",
43 | "isort",
44 | "ruff",
45 | "pytest",
46 | "pytest-cov",
47 | "pytest-sugar",
48 | "hypothesis>=6.112.0",
49 | "commitizen",
50 | ]
51 | docs = [
52 | "mkdocs",
53 | "mkdocs-material",
54 | "mkdocs-material-extensions",
55 | "mkdocstrings",
56 | "mkdocstrings-python",
57 | "mkdocs-autorefs",
58 | "mkdocs-git-committers-plugin-2",
59 | "mkdocs-git-revision-date-localized-plugin",
60 | ]
61 |
62 |
63 | [project.urls]
64 | "Homepage" = "https://shenxiangzhuang.github.io/zhplot"
65 | "Bug Tracker" = "https://shenxiangzhuang.github.io/zhplot/issues"
66 | "Documentation" = "https://shenxiangzhuang.github.io/zhplot"
67 | "Source Code" = "https://github.com/shenxiangzhuang/zhplot"
68 | "Release Notes" = "https://shenxiangzhuang.github.io/zhplot/changelog/"
69 |
70 | [tool.setuptools]
71 | zip-safe = true
72 | include-package-data = true
73 |
74 | [tool.setuptools.packages.find]
75 | include = ["zhplot*"]
76 | namespaces = false
77 |
78 | [tool.setuptools.package-data]
79 | zhplot = ["./fonts/*.ttf", "./fonts/*.txt"]
80 |
81 |
82 | [tool.isort]
83 | profile = "black"
84 |
85 | [tool.ruff]
86 | # Allow lines to be as long as 120.
87 | line-length = 120
88 |
89 | [tool.uv]
90 | extra-index-url = ["https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"]
91 |
--------------------------------------------------------------------------------
/tests/test_matplotlib.py:
--------------------------------------------------------------------------------
1 | import matplotlib.pyplot as plt
2 |
3 | import zhplot # noqa
4 |
5 |
6 | def test_simple_plot():
7 | """Test basic plotting with Chinese labels."""
8 | fig, ax = plt.subplots()
9 | ax.plot([1, 2, 3, 4])
10 | ax.set_xlabel("简单测试")
11 | plt.close(fig)
12 |
13 |
14 | def test_chinese_font_config():
15 | """Test if matplotlib is configured to use Chinese fonts."""
16 | # Check if SimHei is in the font family settings after the import
17 | assert (
18 | "Noto Sans SC" in plt.rcParams["font.family"]
19 | or any("Noto Sans SC" in name.lower() for name in plt.rcParams["font.sans-serif"])
20 | ) is True
21 |
--------------------------------------------------------------------------------
/tests/test_wordcloud.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import zhplot # noqa
4 |
5 |
6 | def test_chinese_font_config():
7 | """Test if wordcloud is configured to use Chinese fonts."""
8 | font_path_env = os.getenv("FONT_PATH")
9 | assert font_path_env is not None
10 | assert "NotoSansSC-Regular" in font_path_env
11 |
--------------------------------------------------------------------------------
/zhplot/__init__.py:
--------------------------------------------------------------------------------
1 | from .matplotlib import matplotlib_chineseize
2 | from .wordcloud import wordcloud_chineseize
3 |
4 | __all__ = [
5 | "matplotlib_chineseize",
6 | "wordcloud_chineseize",
7 | ]
8 |
--------------------------------------------------------------------------------
/zhplot/fonts/NotoSansSC-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shenxiangzhuang/zhplot/f5d6d788fef310d72022037ad7531fa6a84d4473/zhplot/fonts/NotoSansSC-Regular.ttf
--------------------------------------------------------------------------------
/zhplot/fonts/OFL.txt:
--------------------------------------------------------------------------------
1 | Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | https://openfontlicense.org
6 |
7 |
8 | -----------------------------------------------------------
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 |
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded,
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 |
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 |
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 |
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 |
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 |
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 |
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 |
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 |
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 |
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 |
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 |
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 |
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 |
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 |
--------------------------------------------------------------------------------
/zhplot/fonts/README.txt:
--------------------------------------------------------------------------------
1 | Noto Sans SC Variable Font
2 | ==========================
3 |
4 | This download contains Noto Sans SC as both a variable font and static fonts.
5 |
6 | Noto Sans SC is a variable font with this axis:
7 | wght
8 |
9 | This means all the styles are contained in a single file:
10 | NotoSansSC-VariableFont_wght.ttf
11 |
12 | If your app fully supports variable fonts, you can now pick intermediate styles
13 | that aren’t available as static fonts. Not all apps support variable fonts, and
14 | in those cases you can use the static font files for Noto Sans SC:
15 | static/NotoSansSC-Thin.ttf
16 | static/NotoSansSC-ExtraLight.ttf
17 | static/NotoSansSC-Light.ttf
18 | static/NotoSansSC-Regular.ttf
19 | static/NotoSansSC-Medium.ttf
20 | static/NotoSansSC-SemiBold.ttf
21 | static/NotoSansSC-Bold.ttf
22 | static/NotoSansSC-ExtraBold.ttf
23 | static/NotoSansSC-Black.ttf
24 |
25 | Get started
26 | -----------
27 |
28 | 1. Install the font files you want to use
29 |
30 | 2. Use your app's font picker to view the font family and all the
31 | available styles
32 |
33 | Learn more about variable fonts
34 | -------------------------------
35 |
36 | https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
37 | https://variablefonts.typenetwork.com
38 | https://medium.com/variable-fonts
39 |
40 | In desktop apps
41 |
42 | https://theblog.adobe.com/can-variable-fonts-illustrator-cc
43 | https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
44 |
45 | Online
46 |
47 | https://developers.google.com/fonts/docs/getting_started
48 | https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
49 | https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
50 |
51 | Installing fonts
52 |
53 | MacOS: https://support.apple.com/en-us/HT201749
54 | Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
55 | Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
56 |
57 | Android Apps
58 |
59 | https://developers.google.com/fonts/docs/android
60 | https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
61 |
62 | License
63 | -------
64 | Please read the full license text (OFL.txt) to understand the permissions,
65 | restrictions and requirements for usage, redistribution, and modification.
66 |
67 | You can use them in your products & projects – print or digital,
68 | commercial or otherwise.
69 |
70 | This isn't legal advice, please consider consulting a lawyer and see the full
71 | license for all details.
72 |
--------------------------------------------------------------------------------
/zhplot/matplotlib.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from pathlib import Path
3 |
4 | import matplotlib
5 | from matplotlib import font_manager
6 |
7 |
8 | @dataclass
9 | class MatplotlibChineseize:
10 | font_name: str = "Noto Sans SC"
11 | font_ttf: str = "NotoSansSC-Regular.ttf"
12 |
13 | def __post_init__(self):
14 | self.font_dir_path = Path(__file__).parent / "fonts"
15 | self.font_ttf_path = self.font_dir_path / self.font_ttf
16 |
17 | def setup(self):
18 | # Ref: https://github.com/uehara1414/japanize-matplotlib
19 | font_files = font_manager.findSystemFonts(fontpaths=[self.font_dir_path])
20 | for fpath in font_files:
21 | font_manager.fontManager.addfont(fpath)
22 | matplotlib.rc("font", family=self.font_name)
23 |
24 |
25 | def matplotlib_chineseize():
26 | MatplotlibChineseize().setup()
27 |
28 |
29 | matplotlib_chineseize()
30 |
--------------------------------------------------------------------------------
/zhplot/py.typed:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shenxiangzhuang/zhplot/f5d6d788fef310d72022037ad7531fa6a84d4473/zhplot/py.typed
--------------------------------------------------------------------------------
/zhplot/wordcloud.py:
--------------------------------------------------------------------------------
1 | import os
2 | from pathlib import Path
3 |
4 |
5 | def wordcloud_chineseize():
6 | font_ttf: str = "NotoSansSC-Regular.ttf"
7 | os.environ["FONT_PATH"] = f"{Path(__file__).parent}/fonts/{font_ttf}"
8 |
9 |
10 | wordcloud_chineseize()
11 |
--------------------------------------------------------------------------------