├── VERSION ├── tests ├── __init__.py └── sciplot │ ├── baseline │ ├── test_plot_1.png │ ├── test_plot_2.png │ ├── test_style_basic.png │ ├── test_style_clean.png │ ├── test_style_dark.png │ ├── test_style_empty.png │ ├── test_style_serif.png │ ├── test_style_default.png │ ├── test_style_no_latex.png │ ├── test_style_colors_dark.png │ ├── test_style_latex_serif.png │ ├── test_style_typesetting.png │ ├── test_style_colors_light.png │ ├── test_style_locale_en_US.png │ ├── test_style_alpha_beta_gamma.png │ ├── test_style_clean_sans_serif.png │ ├── test_style_fonts_cm_serif.png │ ├── test_style_latex_sans_serif.png │ ├── test_style_no_latex_serif.png │ └── test_style_fonts_cm_sans_serif.png │ └── test_main.py ├── sciplot ├── parameters │ ├── alpha.yml │ ├── beta.yml │ ├── gamma.yml │ ├── no_latex.yml │ ├── fonts_cm_serif.yml │ ├── colors.yml │ ├── fonts_cm_sans_serif.yml │ ├── colors_dark.yml │ ├── colors_light.yml │ ├── typesetting.yml │ ├── latex_serif.yml │ ├── latex_sans_serif.yml │ ├── basic.yml │ └── locales.csv ├── __init__.py └── main.py ├── setup.cfg ├── .markdownlint.yaml ├── example_plots ├── Line_plot_2021-05-23T13.37.png ├── MWE_plot_2021-05-23T13.33.png ├── Histogram_plot_2021-05-23T13.38.png ├── mwe.py └── example_plots.py ├── pyproject.toml ├── CHANGES.txt ├── LICENSE.txt ├── setup.py ├── .github └── workflows │ ├── test.yaml │ └── release.yaml ├── .gitignore ├── update_version.py └── README.md /VERSION: -------------------------------------------------------------------------------- 1 | 0.8.1 -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sciplot/parameters/alpha.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sciplot/parameters/beta.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sciplot/parameters/gamma.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | license_files = LICENSE.txt -------------------------------------------------------------------------------- /sciplot/__init__.py: -------------------------------------------------------------------------------- 1 | from sciplot.main import * # noqa F401 2 | -------------------------------------------------------------------------------- /sciplot/parameters/no_latex.yml: -------------------------------------------------------------------------------- 1 | text.usetex: false # Use LaTeX -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_plot_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_plot_1.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_plot_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_plot_2.png -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | # Linting file for makrdown-cli 2 | default: true 3 | MD013: false 4 | MD032: false 5 | MD033: false 6 | MD036: false -------------------------------------------------------------------------------- /example_plots/Line_plot_2021-05-23T13.37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/example_plots/Line_plot_2021-05-23T13.37.png -------------------------------------------------------------------------------- /example_plots/MWE_plot_2021-05-23T13.33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/example_plots/MWE_plot_2021-05-23T13.33.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_basic.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_clean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_clean.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_dark.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_empty.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_serif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_serif.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_default.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_no_latex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_no_latex.png -------------------------------------------------------------------------------- /example_plots/Histogram_plot_2021-05-23T13.38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/example_plots/Histogram_plot_2021-05-23T13.38.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_colors_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_colors_dark.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_latex_serif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_latex_serif.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_typesetting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_typesetting.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_colors_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_colors_light.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_locale_en_US.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_locale_en_US.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_alpha_beta_gamma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_alpha_beta_gamma.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_clean_sans_serif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_clean_sans_serif.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_fonts_cm_serif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_fonts_cm_serif.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_latex_sans_serif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_latex_sans_serif.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_no_latex_serif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_no_latex_serif.png -------------------------------------------------------------------------------- /tests/sciplot/baseline/test_style_fonts_cm_sans_serif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreasfuhr/sciplot/HEAD/tests/sciplot/baseline/test_style_fonts_cm_sans_serif.png -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | 'setuptools >= 38.6.0', 4 | 'wheel >= 0.31.0', 5 | 'twine >= 1.11.0' 6 | ] 7 | build-backend = 'setuptools.build_meta' -------------------------------------------------------------------------------- /sciplot/parameters/fonts_cm_serif.yml: -------------------------------------------------------------------------------- 1 | # Fonts 2 | font.family: serif 3 | font.serif: Computer Modern # Serif font 4 | mathtext.fontset: cm # Text in math mode 5 | font.size: 7 # General font size -------------------------------------------------------------------------------- /sciplot/parameters/colors.yml: -------------------------------------------------------------------------------- 1 | # Colours 2 | image.cmap: cubehelix # Colourmap 3 | axes.prop_cycle : (cycler('color', ['k', 'r', 'b', 'g']) + cycler('ls', ['-', '--', ':', '-.'])) # Set color and style cycle -------------------------------------------------------------------------------- /sciplot/parameters/fonts_cm_sans_serif.yml: -------------------------------------------------------------------------------- 1 | # Fonts 2 | font.family: sans-serif # Font type 3 | font.serif: Computer Modern Sans Serif # Sans-serif font 4 | mathtext.fontset: cm # Text in math mode 5 | font.size: 7 # General font size -------------------------------------------------------------------------------- /sciplot/parameters/colors_dark.yml: -------------------------------------------------------------------------------- 1 | # Colours 2 | image.cmap: cubehelix # Colourmap 3 | axes.prop_cycle : (cycler('color', ['r', 'b', 'g', 'c', 'm', 'y', 'w']) + cycler('ls', ['-', '--', ':', '-.', '-', '--', ':'])) # Set color and style cycle -------------------------------------------------------------------------------- /sciplot/parameters/colors_light.yml: -------------------------------------------------------------------------------- 1 | # Colours 2 | image.cmap: cubehelix # Colourmap 3 | axes.prop_cycle : (cycler('color', ['k', 'r', 'b', 'g', 'c', 'm', 'y']) + cycler('ls', ['-', '--', ':', '-.', '-', '--', ':'])) # Set color and style cycle -------------------------------------------------------------------------------- /sciplot/parameters/typesetting.yml: -------------------------------------------------------------------------------- 1 | # Title 2 | figure.titlesize: 10 3 | figure.titleweight: bold 4 | axes.titlesize: 9 # Title font size 5 | axes.titleweight: normal # Title font weight 6 | 7 | # Axes 8 | axes.labelsize: 9 # x and y labels font size 9 | axes.labelweight: normal # x and y labels font weight 10 | 11 | # Ticks 12 | xtick.labelsize: 7 # x ticks font size 13 | ytick.labelsize: 7 # y ticks font size 14 | xtick.major.size : 3 15 | ytick.major.size : 3 16 | xtick.minor.size : 1.5 17 | ytick.minor.size : 1.5 18 | 19 | # Legend 20 | legend.fontsize: 6 # Legend font size 21 | legend.edgecolor: grey -------------------------------------------------------------------------------- /CHANGES.txt: -------------------------------------------------------------------------------- 1 | # 0.8.1 2 | 3 | - Fixed typo in setup.py name parameter that caused an incorrect `pip install` command 4 | 5 | # 0.8.0 6 | 7 | - Beta version. 8 | - Updated Sciplot's main module and sciplot.style() and know works with themes (and locale) 9 | - A new testing suite to test the most common features and scenarios, outside of package. There are however still 10 | important tests missing. 11 | - Three empty, ready-to-go user parameter files created: alpha, beta and gamma. 12 | - A new method that prints out all available locale settings (from Oracle) in console 13 | 14 | # 0.7.9 15 | 16 | - Alpha version. 17 | 18 | -------------------------------------------------------------------------------- /sciplot/parameters/latex_serif.yml: -------------------------------------------------------------------------------- 1 | # TODO: Write description 2 | text.usetex: true # Use LaTeX 3 | 4 | # LaTeX standard math and physics preamble with serif font in math mode 5 | text.latex.preamble: > 6 | \usepackage{amsmath} 7 | \usepackage{amssymb} 8 | \usepackage{mathtools} 9 | \usepackage{bbm} 10 | \usepackage{gensymb} 11 | \usepackage[italicdiff]{physics} 12 | \usepackage{icomma} 13 | \usepackage{siunitx} 14 | \sisetup{ 15 | locale=DE, 16 | detect-all, 17 | range-phrase=\text{--}, 18 | seperr, 19 | range-units=single, 20 | bracket-unit-denominator=false, 21 | sticky-per, 22 | per-mode=symbol 23 | } -------------------------------------------------------------------------------- /example_plots/mwe.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import sciplot 4 | from pathlib import Path 5 | 6 | x = np.arange(0, 2 * np.pi, 1e-2) 7 | y1 = np.sin(2 * x + np.pi) 8 | y2 = np.cos(2 * x + np.pi) 9 | 10 | sciplot.set_size_cm(5) 11 | 12 | with sciplot.style(): 13 | plt.plot(x, y1, x, y2) 14 | plt.xticks( 15 | np.linspace(0, 2 * np.pi, 5), 16 | ['$0$', r'$\frac{\pi}{2}$', r'$\pi$', r'$\frac{3\pi}{2}$', r'$2\pi$'] 17 | ) 18 | 19 | sciplot.save_time_stamped_figure( 20 | plot_file_name='MWE_plot', 21 | save_directory=(Path(__file__).parent) 22 | ) 23 | plt.show() 24 | -------------------------------------------------------------------------------- /sciplot/parameters/latex_sans_serif.yml: -------------------------------------------------------------------------------- 1 | # TODO: Write description 2 | text.usetex: true # Use LaTeX 3 | 4 | # LaTeX standard math and physics preamble with sans-serif font in math mode 5 | text.latex.preamble: > 6 | \usepackage{amsmath} 7 | \usepackage{amssymb} 8 | \usepackage{mathtools} 9 | \usepackage{bbm} 10 | \usepackage{gensymb} 11 | \usepackage[italicdiff]{physics} 12 | \usepackage{icomma} 13 | \usepackage{sansmath} 14 | \sansmath 15 | \usepackage{siunitx} 16 | \sisetup{ 17 | locale=DE, 18 | detect-all, 19 | range-phrase=\text{--}, 20 | seperr, 21 | range-units=single, 22 | bracket-unit-denominator=false, 23 | sticky-per, 24 | per-mode=symbol 25 | } -------------------------------------------------------------------------------- /sciplot/parameters/basic.yml: -------------------------------------------------------------------------------- 1 | figure.autolayout: True # Automatic figure layout 2 | figure.subplot.left : 0.5 3 | figure.dpi : 600 4 | savefig.bbox : tight # Always save as 'tight' 5 | savefig.pad_inches : 0.04 6 | 7 | 8 | 9 | # Linewidths 10 | axes.linewidth: 0.25 # Border linewidth 11 | grid.linewidth: 0.25 # Grid linewidth 12 | xtick.major.width: 0.25 # x ticks major linewidth 13 | xtick.minor.width: 0.25 # x ticks minor linewidth 14 | ytick.major.width: 0.25 # y ticks major linewidth 15 | ytick.minor.width: 0.25 # y ticks minor linewidth 16 | 17 | # Plots 18 | lines.linewidth : 0.5 # Width of plotted lines 19 | lines.markersize : 2 # Size of plotted markers 20 | 21 | # Axes 22 | axes.formatter.use_locale: True # Use local decimal separator etc. 23 | axes.grid: False # Grid turned off 24 | 25 | # Ticks 26 | xtick.direction : in 27 | ytick.direction : in 28 | xtick.minor.visible : True 29 | ytick.minor.visible : True 30 | xtick.top : True 31 | ytick.right : True 32 | 33 | # Legend 34 | patch.linewidth: 0.25 35 | legend.frameon: True 36 | legend.fancybox: False 37 | legend.loc: upper left -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Andreas Führ 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 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open('README.md', 'r', encoding='utf-8') as fh: 4 | long_description = fh.read() 5 | 6 | setuptools.setup( 7 | name='sciplot', 8 | version='0.8.1', 9 | author='Andreas Führ', 10 | author_email='andreas.fuhr@outlook.com', 11 | license='MIT', 12 | description='Format Matplotlib scientific plots', 13 | long_description=long_description, 14 | long_description_content_type='text/markdown', 15 | url='https://github.com/andreasfuhr/sciplot', 16 | classifiers=[ 17 | 'Programming Language :: Python :: 3.7', 18 | 'Programming Language :: Python :: 3.8', 19 | 'Programming Language :: Python :: 3.9', 20 | 'License :: OSI Approved :: MIT License', 21 | 'Operating System :: OS Independent', 22 | 'Development Status :: 4 - Beta', 23 | 'Natural Language :: English', 24 | 'Framework :: Matplotlib', 25 | 'Topic :: Scientific/Engineering' 26 | ], 27 | packages=['sciplot'], 28 | package_data={'sciplot': ['parameters/*.yml', '../README.md']}, 29 | include_package_data=True, 30 | python_requires='>=3.7', 31 | install_requires=['matplotlib>=3.3.4', 'pyyaml', 'seaborn'], 32 | ) 33 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | 3 | name: Test Python package 4 | 5 | on: [push] 6 | 7 | jobs: 8 | lint: 9 | name: Lint package files 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Set up Python 3.9 14 | uses: actions/setup-python@v2 15 | with: 16 | python-version: 3.9 17 | - name: Install dependencies 18 | run: | 19 | python -m pip install --upgrade pip 20 | pip install pylint 21 | python -m pip install flake8 22 | pip install -e . 23 | - name: Python linting with flake8 24 | run: | 25 | flake8 . --count --max-complexity=10 --max-line-length=127 --show-source --statistics --format=pylint --exit-zero 26 | - name: Markdown and YAML lintning with markdownlint-cli 27 | uses: nosborn/github-action-markdown-cli@v2.0.0 28 | with: 29 | files: . 30 | config_file: .markdownlint.yaml 31 | test: 32 | name: Test package 33 | runs-on: ubuntu-latest 34 | strategy: 35 | fail-fast: false 36 | steps: 37 | - uses: actions/checkout@v2 38 | - name: Set up Python 3.9 39 | uses: actions/setup-python@v2 40 | with: 41 | python-version: 3.9 42 | - name: Prepare Github Actions 43 | uses: actions/checkout@v2 44 | - name: Install TeXLive 45 | uses: xu-cheng/texlive-action/full@v1 46 | - name: Set up Python ${{ matrix.python-version }} 47 | uses: actions/setup-python@v2 48 | with: 49 | python-version: ${{ matrix.python-version }} 50 | - name: Install dependencies 51 | run: | 52 | python -m pip install --upgrade pip 53 | python -m pip install pytest 54 | python -m pip install pytest-mpl 55 | pip install -e . 56 | - name: Test with pytest 57 | run: | 58 | sudo locale-gen en_US.UTF-8 59 | sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 60 | pytest --mpl-baseline-relative -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # PyCharm settings 132 | .idea/ 133 | .DS_Store 134 | -------------------------------------------------------------------------------- /example_plots/example_plots.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.stats import pareto 3 | import matplotlib.pyplot as plt 4 | from matplotlib.patches import Rectangle 5 | from pathlib import Path 6 | 7 | import sciplot 8 | 9 | # Plot 1 10 | with sciplot.style(theme='no-latex', locale_setting='en_US.UTF-8'): 11 | x_m = 2 # scale 12 | alpha_lst = [1, 2, 3, 4] # shape parameters 13 | x = np.linspace(0, 6, 1000) 14 | 15 | pdf = np.array([pareto.pdf(x, scale=x_m, b=a) for a in alpha_lst]) 16 | 17 | sciplot.set_size_cm(7) 18 | fig, ax = plt.subplots(1, 1) 19 | 20 | fig.suptitle(r'Pareto PDF' + 21 | r' $p(x \,|\, x_\mathrm{m}, \alpha) = \frac{\alpha x_\mathrm{m}^\alpha}{x^{\alpha+1}}$' + 22 | r' with $x_\mathrm{m}=2$') 23 | 24 | line_plot = ax.plot(x, pdf.T) 25 | 26 | label_lst = [] 27 | for alpha in alpha_lst: 28 | label_lst.append(r'$\alpha=' + str(alpha) + '$') 29 | 30 | sciplot.set_legend( 31 | ax=ax, 32 | plot_tpl=line_plot, 33 | label_tpl=tuple(label_lst), 34 | loc='upper right' 35 | ) 36 | 37 | ax.set_xlabel('$x$') 38 | ax.set_ylabel(r'$p(x \,|\, x_\mathrm{m}, \alpha)$') 39 | 40 | sciplot.save_time_stamped_figure( 41 | plot_file_name='Line_plot', 42 | save_directory=(Path(__file__).parent) 43 | ) 44 | 45 | plt.show() 46 | 47 | 48 | # Plot 2 49 | with sciplot.style(theme=['no-latex', 'dark'], locale_setting='en_US.UTF-8'): 50 | np.random.seed(42) 51 | n = 10000 52 | mean_ar = np.array([4.5, 6.1, 8.3]) 53 | std_ar = np.array([0.2, 0.9, 0.5]) 54 | data_ar = np.array([ 55 | np.random.normal(mean_ar[0], std_ar[0], n), 56 | np.random.normal(mean_ar[1], std_ar[1], n), 57 | np.random.normal(mean_ar[2], std_ar[2], n) 58 | ]) 59 | 60 | sciplot.set_size_cm(16, 8) 61 | fig, ax = plt.subplots(1, 1) 62 | 63 | fig.suptitle(r'Histogram of normally distributed velocities with \SI{' + str(n) + r'}{} samples') 64 | 65 | plot_lst = [] 66 | color_lst = sciplot.get_color_lst(len(data_ar), seaborn_color_map='rocket', colorful=False) 67 | 68 | for i, data in enumerate(data_ar): 69 | ax.hist(data, density=True, bins=100, alpha=0.7, color=color_lst[i]) 70 | plot_lst.append(Rectangle((0, 0), 1, 1, color=color_lst[i], alpha=0.7)) 71 | 72 | label_lst = [] 73 | for i in range(len(data_ar)): 74 | label_lst.append(r'$\mu=\SI{' + str(mean_ar[i]) + r'}{}$, $\sigma=\SI{' + str(std_ar[i]) + r'}{}$') 75 | 76 | sciplot.set_legend( 77 | ax=ax, 78 | plot_tpl=tuple(plot_lst), 79 | label_tpl=tuple(label_lst), 80 | loc='lower right', 81 | outside_plot=True 82 | ) 83 | 84 | ax.set_xlabel(r'Velocity (\si{\metre\per\second})') 85 | ax.set_ylabel(r'Relative frequency') 86 | 87 | sciplot.save_time_stamped_figure( 88 | plot_file_name='Histogram_plot', 89 | save_directory=(Path(__file__).parent) 90 | ) 91 | 92 | plt.show() 93 | -------------------------------------------------------------------------------- /update_version.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import pathlib 3 | import re 4 | 5 | 6 | VERSION_REGEX_STR = r'[0-9]+\.[0-9]+\.[0-9]+' 7 | VERSION_V_REGEX_STR = r'v[0-9]+\.[0-9]+\.[0-9]+' 8 | 9 | IN_FILE_VERSION_REGEX_DICT = { 10 | 'changes': { 11 | 'file_name': 'CHANGES.txt' 12 | }, 13 | 'version': { 14 | 'file_name': 'VERSION', 15 | 'version_prefix': '', 16 | 'version_suffix': '' 17 | }, 18 | 'readme': { 19 | 'file_name': 'README.md', 20 | 'version_prefix': r'{', 21 | 'version_suffix': r'}' 22 | }, 23 | 'setup': { 24 | 'file_name': 'setup.py', 25 | 'version_prefix': r"version='", 26 | 'version_suffix': "'" 27 | }, 28 | } 29 | 30 | 31 | def version_regex_type(arg_value, pat=re.compile(VERSION_REGEX_STR)): 32 | if not pat.match(arg_value): 33 | alt_version_val = re.compile(VERSION_V_REGEX_STR) 34 | if alt_version_val.match(arg_value): 35 | arg_value = arg_value[1:] 36 | else: 37 | raise argparse.ArgumentTypeError 38 | return arg_value 39 | 40 | 41 | def check_changes(file_path, file_type_dict, version_new): 42 | with open(file_path, 'r') as file: 43 | content = file.read() 44 | 45 | result_lst = re.findall(version_new, content) 46 | if version_new not in result_lst: 47 | raise ValueError( 48 | "Changes list " + file_type_dict['file_name'] + " not updated for version '" + 49 | version_new + "'.") 50 | 51 | print('Checked version in ' + file_type_dict['file_name']) 52 | 53 | 54 | def update_file(file_path, file_type_dict, version_new): 55 | with open(file_path, 'r') as file: 56 | content = file.read() 57 | 58 | content_new = re.sub( 59 | file_type_dict['version_prefix'] + VERSION_REGEX_STR + file_type_dict['version_suffix'], 60 | file_type_dict['version_prefix'] + version_new + file_type_dict['version_suffix'], 61 | content, 62 | flags=re.M 63 | ) 64 | 65 | with open(file_path, 'w') as file: 66 | file.write(content_new) 67 | 68 | print("Updated version in " + file_type_dict['file_name'] + " to '" + version_new + "'") 69 | 70 | 71 | def main(version_new): 72 | # Get all files in directory . 73 | file_path_lst = [str(p.absolute()) for p in pathlib.Path('.').iterdir() if p.is_file()] 74 | 75 | for file_type in ['changes', 'version', 'readme', 'setup']: 76 | file_type_dict = IN_FILE_VERSION_REGEX_DICT[file_type] 77 | for file_path in file_path_lst: 78 | if file_type == 'changes' and file_path.endswith(file_type_dict['file_name']): 79 | check_changes(file_path, file_type_dict, version_new) 80 | continue 81 | 82 | if file_path.endswith(file_type_dict['file_name']): 83 | update_file(file_path, file_type_dict, version_new) 84 | continue 85 | 86 | 87 | if __name__ == '__main__': 88 | PARSER = argparse.ArgumentParser() 89 | PARSER.add_argument( 90 | '-v', 91 | '--version', 92 | type=version_regex_type, 93 | help='Semantic version, e.g. 1.2.3 or v1.2.3', 94 | required=True 95 | ) 96 | ARGS = PARSER.parse_args() 97 | 98 | main(ARGS.version) 99 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions and releases the 2 | # package on GitHub and to PyPI. It also increments the semantic version. 3 | 4 | name: Release Python package 5 | 6 | on: 7 | push: 8 | # Sequence of patterns matched against refs/tags 9 | tags: 10 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 11 | 12 | jobs: 13 | lint: 14 | name: Lint package files 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Set up Python 3.9 19 | uses: actions/setup-python@v2 20 | with: 21 | python-version: 3.9 22 | - name: Install dependencies 23 | run: | 24 | python -m pip install --upgrade pip 25 | pip install pylint 26 | python -m pip install flake8 27 | pip install -e . 28 | - name: Python linting with flake8 29 | run: | 30 | flake8 . --count --max-complexity=10 --max-line-length=127 --show-source --statistics --format=pylint --exit-zero 31 | - name: Markdown and YAML lintning with markdownlint-cli 32 | uses: nosborn/github-action-markdown-cli@v2.0.0 33 | with: 34 | files: . 35 | config_file: .yaml 36 | test: 37 | name: Run package tests 38 | needs: linting 39 | runs-on: ${{matrix.os}} 40 | strategy: 41 | fail-fast: true 42 | matrix: 43 | python-version: [3.7, 3.8, 3.9] 44 | os: [ubuntu-latest, windows-latest, macos-latest] 45 | steps: 46 | - name: Prepare Github Actions 47 | uses: actions/checkout@v2 48 | - name: Install TeXLive 49 | uses: xu-cheng/texlive-action/full@v1 50 | - name: Set up Python ${{ matrix.python-version }} 51 | uses: actions/setup-python@v2 52 | with: 53 | python-version: ${{ matrix.python-version }} 54 | - name: Install dependencies 55 | run: | 56 | python -m pip install --upgrade pip 57 | python -m pip install pytest 58 | python -m pip install pytest-mpl 59 | pip install -e . 60 | - name: Test with pytest 61 | run: | 62 | sudo locale-gen en_US.UTF-8 63 | sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 64 | pytest --mpl-baseline-relative 65 | release-prep: 66 | name: Prepare release 67 | needs: testing 68 | runs-on: ubuntu-latest 69 | steps: 70 | - uses: actions/checkout@v2 71 | - name: Update version in repo 72 | run: python3 update_version.py --version ${{ github.event.release.tag_name }} 73 | - name: Commit files 74 | run: | 75 | git config --local user.name "Sciplot release workflow" 76 | git add . 77 | git commit -m "[RELEASE] Incremented semantic version" 78 | - name: Push changes to Github 79 | uses: ad-m/github-push-action@master 80 | with: 81 | github_token: ${{ secrets.GITHUB_TOKEN }} 82 | force: true 83 | - name: Update GitHub repo version badge 84 | uses: schneegans/dynamic-badges-action@v1.1.0 85 | with: 86 | auth: ${{ secrets.GIST_SECRET }} 87 | gistID: ae1a5002566bdc7d8d143aab72331657 88 | filename: Sciplot-github-version.json 89 | label: repo 90 | message: ${{ github.event.release.tag_name }} 91 | color: blue 92 | style: flat 93 | logo: github 94 | - name: Update PyPI version badge 95 | uses: schneegans/dynamic-badges-action@v1.1.0 96 | with: 97 | auth: ${{ secrets.GIST_SECRET }} 98 | gistID: 38e0946c4456d70028d4482fe18dcc45 99 | filename: Sciplot-pypi-version.json 100 | label: repo 101 | message: ${{ github.event.release.tag_name }} 102 | color: blue 103 | style: flat 104 | logo: github 105 | release: 106 | name: Create release 107 | needs: release-prep 108 | runs-on: ubuntu-latest 109 | steps: 110 | - name: Checkout code 111 | uses: actions/checkout@master 112 | - name: Create Release 113 | id: create_release 114 | uses: actions/create-release@v1 115 | env: 116 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token 117 | with: 118 | tag_name: ${{ github.ref }} 119 | release_name: Release ${{ github.ref }} 120 | body: | 121 | Changes in this Release 122 | draft: false 123 | prerelease: false 124 | deploy: 125 | name: Publish package to PyPI 126 | needs: release 127 | runs-on: ubuntu-latest 128 | steps: 129 | - uses: actions/checkout@v1 130 | - name: Set up Python 131 | uses: actions/setup-python@v1 132 | with: 133 | python-version: '3.x' 134 | - name: Install dependencies 135 | run: | 136 | python -m pip install --upgrade pip 137 | pip install setuptools wheel twine 138 | - name: Build and publish 139 | env: 140 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 141 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 142 | run: | 143 | python setup.py sdist bdist_wheel 144 | twine upload dist/* -------------------------------------------------------------------------------- /tests/sciplot/test_main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | import numpy as np 4 | from scipy.stats import pareto 5 | import matplotlib.pyplot as plt 6 | from matplotlib.patches import Rectangle 7 | from pathlib import Path 8 | import locale 9 | 10 | sys.path.append(str(Path(__file__).parent / '..' / '..')) 11 | import sciplot.main as sciplot # noqa: E402 12 | 13 | locale.setlocale(locale.LC_NUMERIC, 'en_US.UTF-8') 14 | 15 | 16 | def test_get_parameters_dir(): 17 | parameters_dir = str(Path(__file__).parent / '..' / '..' / 'sciplot' / 'parameters') 18 | print(parameters_dir) 19 | assert '/'.split(sciplot.get_parameters_dir())[-4:] == '/'.split(str(parameters_dir))[-4:] 20 | 21 | 22 | def test_get_theme_priority_lst(): 23 | theme_priority_lst = [ 24 | 'alpha', 25 | 'beta', 26 | 'gamma', 27 | 'no-latex', 28 | 'serif', 29 | 'sans-serif', 30 | 'dark', 31 | 'default' 32 | ] 33 | assert sciplot.get_theme_priority_lst() == theme_priority_lst 34 | 35 | 36 | def test_get_theme_lst_with_string(): 37 | theme = 'theme' 38 | assert sciplot._get_theme_lst(theme) == [theme] 39 | 40 | 41 | def test_get_theme_lst_with_capital_string(): 42 | theme = 'THEME' 43 | assert sciplot._get_theme_lst(theme) == [theme.lower()] 44 | 45 | 46 | def test_get_theme_lst_with_list(): 47 | theme = ['theme1', 'theme2'] 48 | assert sciplot._get_theme_lst(theme) == theme 49 | 50 | 51 | def test_get_theme_lst_with_float(): 52 | theme = 100. 53 | with pytest.raises(sciplot.SciplotException): 54 | sciplot._get_theme_lst(theme) 55 | 56 | 57 | def test_get_theme_lst_with_float_in_list(): 58 | theme = ['theme1', 100.] 59 | with pytest.raises(sciplot.SciplotException): 60 | sciplot._get_theme_lst(theme) 61 | 62 | 63 | def test_color_lst_one_color(): 64 | color_no = 1 65 | color_lst = ['#000000'] 66 | assert sciplot.get_color_lst(color_no) == color_lst 67 | 68 | 69 | def test_color_lst_zero_colors(): 70 | color_no = 0 71 | with pytest.raises(sciplot.SciplotException): 72 | sciplot.get_color_lst(color_no) 73 | 74 | 75 | def test_color_lst_float_color_no(): 76 | color_no = 2.5 77 | with pytest.raises(sciplot.SciplotException): 78 | sciplot.get_color_lst(color_no) 79 | 80 | 81 | # Does not work ATM 82 | def test_style_locale_incorrect(): 83 | local = 'Undefined_local' 84 | x = np.linspace(0, 1, 2) 85 | y = 2 * x 86 | with pytest.raises(locale.Error): 87 | with sciplot.style(locale_setting=local): 88 | plt.plot(x, y) 89 | return plt.gcf() 90 | 91 | 92 | def test_get_available_locals(): 93 | sciplot.get_available_locals() 94 | 95 | 96 | @pytest.mark.mpl_image_compare 97 | def test_style_empty(): 98 | x = np.linspace(0, 1, 2) 99 | y = 2 * x 100 | with sciplot.style(locale_setting='en_US.UTF-8'): 101 | plt.plot(x, y) 102 | return plt.gcf() 103 | 104 | 105 | @pytest.mark.mpl_image_compare 106 | def test_style_default(): 107 | x = np.linspace(0, 1, 2) 108 | y = 2 * x 109 | with sciplot.style(locale_setting='en_US.UTF-8'): 110 | plt.plot(x, y) 111 | return plt.gcf() 112 | 113 | 114 | @pytest.mark.mpl_image_compare 115 | def test_style_clean(): 116 | x = np.linspace(0, 1, 2) 117 | y = 2 * x 118 | with sciplot.style(theme='clean', locale_setting='en_US.UTF-8'): 119 | plt.plot(x, y) 120 | return plt.gcf() 121 | 122 | 123 | @pytest.mark.mpl_image_compare 124 | def test_style_dark(): 125 | x = np.linspace(0, 1, 2) 126 | y = 2 * x 127 | with sciplot.style(theme='dark', locale_setting='en_US.UTF-8'): 128 | plt.plot(x, y) 129 | return plt.gcf() 130 | 131 | 132 | @pytest.mark.mpl_image_compare 133 | def test_style_serif(): 134 | x = np.linspace(0, 1, 2) 135 | y = 2 * x 136 | with sciplot.style(theme='serif', locale_setting='en_US.UTF-8'): 137 | plt.plot(x, y) 138 | return plt.gcf() 139 | 140 | 141 | @pytest.mark.mpl_image_compare 142 | def test_style_clean_sans_serif(): 143 | x = np.linspace(0, 1, 2) 144 | y = 2 * x 145 | with sciplot.style(theme=['clean', 'sans-serif'], locale_setting='en_US.UTF-8'): 146 | plt.plot(x, y) 147 | return plt.gcf() 148 | 149 | 150 | @pytest.mark.mpl_image_compare 151 | def test_style_no_latex(): 152 | x = np.linspace(0, 1, 2) 153 | y = 2 * x 154 | with sciplot.style(theme='no-latex', locale_setting='en_US.UTF-8'): 155 | plt.plot(x, y) 156 | return plt.gcf() 157 | 158 | 159 | @pytest.mark.mpl_image_compare 160 | def test_style_no_latex_serif(): 161 | x = np.linspace(0, 1, 2) 162 | y = 2 * x 163 | with sciplot.style(theme=['no-latex', 'serif'], locale_setting='en_US.UTF-8'): 164 | plt.plot(x, y) 165 | return plt.gcf() 166 | 167 | 168 | @pytest.mark.mpl_image_compare 169 | def test_style_basic(): 170 | x = np.linspace(0, 1, 2) 171 | y = 2 * x 172 | with sciplot.style(theme='basic', locale_setting='en_US.UTF-8'): 173 | plt.plot(x, y) 174 | return plt.gcf() 175 | 176 | 177 | @pytest.mark.mpl_image_compare 178 | def test_style_typesetting(): 179 | x = np.linspace(0, 1, 2) 180 | y = 2 * x 181 | with sciplot.style(theme='typesetting', locale_setting='en_US.UTF-8'): 182 | plt.plot(x, y) 183 | return plt.gcf() 184 | 185 | 186 | @pytest.mark.mpl_image_compare 187 | def test_style_colors_light(): 188 | x = np.linspace(0, 1, 2) 189 | y = 2 * x 190 | with sciplot.style(theme='colors_light', locale_setting='en_US.UTF-8'): 191 | plt.plot(x, y) 192 | return plt.gcf() 193 | 194 | 195 | @pytest.mark.mpl_image_compare 196 | def test_style_colors_dark(): 197 | x = np.linspace(0, 1, 2) 198 | y = 2 * x 199 | with sciplot.style(theme='colors_dark', locale_setting='en_US.UTF-8'): 200 | plt.plot(x, y) 201 | return plt.gcf() 202 | 203 | 204 | @pytest.mark.mpl_image_compare 205 | def test_style_fonts_cm_sans_serif(): 206 | x = np.linspace(0, 1, 2) 207 | y = 2 * x 208 | with sciplot.style(theme='fonts_cm_sans_serif', locale_setting='en_US.UTF-8'): 209 | plt.plot(x, y) 210 | return plt.gcf() 211 | 212 | 213 | @pytest.mark.mpl_image_compare 214 | def test_style_fonts_cm_serif(): 215 | x = np.linspace(0, 1, 2) 216 | y = 2 * x 217 | with sciplot.style(theme='fonts_cm_serif', locale_setting='en_US.UTF-8'): 218 | plt.plot(x, y) 219 | return plt.gcf() 220 | 221 | 222 | @pytest.mark.mpl_image_compare 223 | def test_style_latex_sans_serif(): 224 | x = np.linspace(0, 1, 2) 225 | y = 2 * x 226 | with sciplot.style(theme='latex_sans_serif', locale_setting='en_US.UTF-8'): 227 | plt.plot(x, y) 228 | return plt.gcf() 229 | 230 | 231 | @pytest.mark.mpl_image_compare 232 | def test_style_latex_serif(): 233 | x = np.linspace(0, 1, 2) 234 | y = 2 * x 235 | with sciplot.style(theme='latex_serif', locale_setting='en_US.UTF-8'): 236 | plt.plot(x, y) 237 | return plt.gcf() 238 | 239 | 240 | @pytest.mark.mpl_image_compare 241 | def test_style_alpha_beta_gamma(): 242 | x = np.linspace(0, 1, 2) 243 | y = 2 * x 244 | with sciplot.style(['alpha', 'beta', 'gamma'], locale_setting='en_US.UTF-8'): 245 | plt.plot(x, y) 246 | return plt.gcf() 247 | 248 | 249 | # Plot 1 250 | @pytest.mark.mpl_image_compare 251 | def test_plot_1(): 252 | with sciplot.style(locale_setting='en_US.UTF-8'): 253 | x_m = 2 # scale 254 | alpha_lst = [1, 2, 3, 4] # shape parameters 255 | x = np.linspace(0, 6, 1000) 256 | 257 | pdf = np.array([pareto.pdf(x, scale=x_m, b=a) for a in alpha_lst]) 258 | 259 | sciplot.set_size_cm(7) 260 | fig, ax = plt.subplots(1, 1) 261 | 262 | fig.suptitle(r'Pareto PDF' + 263 | r' $p(x \,|\, x_\mathrm{m}, \alpha) = \frac{\alpha x_\mathrm{m}^\alpha}{x^{\alpha+1}}$' + 264 | r' with $x_\mathrm{m}=2$') 265 | 266 | line_plot = ax.plot(x, pdf.T) 267 | 268 | label_lst = [] 269 | for alpha in alpha_lst: 270 | label_lst.append(r'$\alpha=' + str(alpha) + '$') 271 | 272 | sciplot.set_legend( 273 | ax=ax, 274 | plot_tpl=line_plot, 275 | label_tpl=tuple(label_lst), 276 | loc='upper right' 277 | ) 278 | 279 | ax.set_xlabel('$x$') 280 | ax.set_ylabel(r'$p(x \,|\, x_\mathrm{m}, \alpha)$') 281 | 282 | return fig 283 | 284 | 285 | # Plot 2 286 | @pytest.mark.mpl_image_compare 287 | def test_plot_2(): 288 | with sciplot.style(locale_setting='en_US.UTF-8'): 289 | np.random.seed(42) 290 | n = 10000 291 | mean_ar = np.array([4.5, 6.1, 8.3]) 292 | std_ar = np.array([0.2, 0.9, 0.5]) 293 | data_ar = np.array([ 294 | np.random.normal(mean_ar[0], std_ar[0], n), 295 | np.random.normal(mean_ar[1], std_ar[1], n), 296 | np.random.normal(mean_ar[2], std_ar[2], n) 297 | ]) 298 | 299 | sciplot.set_size_cm(16, 8) 300 | fig, ax = plt.subplots(1, 1) 301 | 302 | fig.suptitle('Histogram of normally distributed velocities with ' + str(n) + ' samples') 303 | 304 | plot_lst = [] 305 | color_lst = sciplot.get_color_lst(len(data_ar), seaborn_color_map='rocket', colorful=False) 306 | 307 | for i, data in enumerate(data_ar): 308 | ax.hist(data, density=True, bins=100, alpha=0.7, color=color_lst[i]) 309 | plot_lst.append(Rectangle((0, 0), 1, 1, color=color_lst[i], alpha=0.7)) 310 | 311 | label_lst = [] 312 | for i in range(len(data_ar)): 313 | label_lst.append(r'$\mu=' + str(mean_ar[i]) + r'$, $\sigma=' + str(std_ar[i]) + r'$') 314 | 315 | sciplot.set_legend( 316 | ax=ax, 317 | plot_tpl=tuple(plot_lst), 318 | label_tpl=tuple(label_lst), 319 | loc='lower right', 320 | outside_plot=True 321 | ) 322 | 323 | ax.set_xlabel('Velocity (m/s)') 324 | ax.set_ylabel(r'Relative frequency') 325 | 326 | return fig 327 | -------------------------------------------------------------------------------- /sciplot/main.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import csv 3 | import locale 4 | import logging 5 | import os 6 | import re 7 | import warnings 8 | from datetime import datetime 9 | from pathlib import Path 10 | from typing import List, Tuple, Union, OrderedDict 11 | import matplotlib 12 | import matplotlib.pyplot as plt 13 | import seaborn as sns 14 | import yaml 15 | 16 | # Reset Matplotlib style library (use in case of unresolved errors) 17 | # plt.style.reload_library() 18 | 19 | # Disable "findfont: Font family ['serif'] not found. Falling back to DejaVu Sans." 20 | logging.getLogger('matplotlib.font_manager').disabled = True 21 | 22 | # Dark mode boolean operator 23 | dark_mode = False 24 | 25 | 26 | # sciplot warning class 27 | class SciplotWarning(UserWarning): 28 | pass 29 | 30 | 31 | # sciplot exception class 32 | class SciplotException(Exception): 33 | pass 34 | 35 | 36 | def _get_theme_lst(theme_input): 37 | theme_lst = [] 38 | if isinstance(theme_input, str): 39 | theme_lst.append(theme_input) 40 | elif isinstance(theme_input, list): 41 | for theme in theme_input: 42 | if not isinstance(theme, str): 43 | raise SciplotException( 44 | "Incorrect theme input type in list for theme '" + 45 | str(theme) + 46 | "': '" + 47 | str(type(theme_input)) + 48 | "'. Correct input type is 'str'.") 49 | theme_lst = theme_input 50 | else: 51 | raise SciplotException( 52 | "Incorrect theme input type: '" + 53 | str(type(theme_input)) + 54 | "'. Correct input type is 'str' or 'list'.") 55 | 56 | # Remove double entries and make theme inputs lowercase 57 | theme_lst = [theme.lower() for theme in OrderedDict.fromkeys(theme_lst)] 58 | 59 | return theme_lst 60 | 61 | 62 | def _get_default_theme_lst( 63 | theme_lst: List[str] 64 | ) -> List[str]: 65 | if 'clean' in theme_lst: 66 | if 'default' in theme_lst: 67 | theme_lst.remove('default') 68 | 69 | theme_lst.remove('clean') 70 | else: 71 | if 'default' not in theme_lst: 72 | theme_lst.append('default') 73 | 74 | return theme_lst 75 | 76 | 77 | def _get_parameter_file_lst( 78 | theme: str 79 | ) -> List[str]: 80 | if theme == 'default': 81 | parameter_file_lst = ['basic', 'typesetting', 'colors_light', 'fonts_cm_sans_serif', 'latex_sans_serif'] 82 | elif theme == 'dark': 83 | plt.style.use('dark_background') 84 | global dark_mode 85 | dark_mode = True 86 | parameter_file_lst = ['colors_dark'] 87 | elif theme == 'serif': 88 | parameter_file_lst = ['fonts_cm_serif', 'latex_serif'] 89 | elif theme == 'sans-serif': 90 | parameter_file_lst = ['fonts_cm_sans_serif', 'latex_sans_serif'] 91 | elif theme == 'no-latex': 92 | parameter_file_lst = ['no_latex'] 93 | else: 94 | parameter_file_lst = [theme] 95 | 96 | return parameter_file_lst 97 | 98 | 99 | def _theme_exists( 100 | theme: str 101 | ) -> bool: 102 | if not (theme in get_theme_priority_lst()): 103 | try: 104 | parameters_dir = Path(__file__).parent / 'parameters' 105 | parameters_path = parameters_dir / (theme + '.yml') 106 | with parameters_path.open(): 107 | pass 108 | return True 109 | except FileNotFoundError: 110 | warnings.warn("Invalid theme ignored by Sciplot: '" + theme + "'", SciplotWarning) 111 | return False 112 | else: 113 | return False 114 | 115 | 116 | def _get_parameters_lst( 117 | parameter_file_lst: List[str] 118 | ) -> List[object]: 119 | # Empty list of parameters 120 | parameters_lst = [] 121 | 122 | parameters_dir = Path(__file__).parent / 'parameters' 123 | 124 | # Import parameters 125 | for parameter_file in parameter_file_lst: 126 | try: 127 | parameters_path = parameters_dir / (parameter_file + '.yml') 128 | with parameters_path.open() as setup_file: 129 | parameters = yaml.safe_load(setup_file.read()) 130 | if parameters: 131 | parameters_lst.append(parameters) 132 | except FileNotFoundError: 133 | raise SciplotException( 134 | "Unable to import theme parameter file: '" + parameter_file + "'") 135 | 136 | return parameters_lst 137 | 138 | 139 | @contextlib.contextmanager 140 | def style( 141 | theme: Union[str, List[str]] = 'default', 142 | locale_setting: str = 'sv_SE' 143 | ): 144 | # Set locale (to get correct decimal separater etc) 145 | locale.setlocale(locale.LC_NUMERIC, locale_setting) 146 | 147 | # Get requested themes as list 148 | theme_lst = _get_theme_lst(theme) 149 | 150 | # Get list with or without default theme 151 | theme_lst = _get_default_theme_lst(theme_lst) 152 | 153 | # Get ordered list if parameter files 154 | parameter_file_lst = [] 155 | theme_priority_lst = get_theme_priority_lst() 156 | theme_priority_lst.reverse() 157 | 158 | # Add themes' associated parameter files to list 159 | for theme_priority in theme_priority_lst: 160 | for theme in theme_lst: 161 | if theme == theme_priority: 162 | parameter_file_lst += _get_parameter_file_lst(theme) 163 | 164 | # Add user defined themes to parameter_file_lst 165 | if any(theme not in theme_priority_lst for theme in theme_lst): 166 | for theme in theme_lst: 167 | if _theme_exists(theme): 168 | parameter_file_lst += _get_parameter_file_lst(theme) 169 | 170 | # Get list of parameter objects from file list 171 | parameters_lst = _get_parameters_lst(parameter_file_lst) 172 | 173 | # Set all parameters in list 174 | for parameters in parameters_lst: 175 | plt.rcParams.update(parameters) 176 | 177 | yield 178 | 179 | plt.style.use('default') 180 | global dark_mode 181 | dark_mode = False 182 | 183 | 184 | def get_parameters_dir() -> str: 185 | return str(Path(__file__).parent / 'parameters') 186 | 187 | 188 | def get_theme_priority_lst() -> List[str]: 189 | theme_priority_lst = [ 190 | 'alpha', 191 | 'beta', 192 | 'gamma', 193 | 'no-latex', 194 | 'serif', 195 | 'sans-serif', 196 | 'dark', 197 | 'default' 198 | ] 199 | return theme_priority_lst 200 | 201 | 202 | def get_available_locals(): 203 | locales_file_path = Path(__file__).parent / 'parameters' / 'locales.csv' 204 | with open(locales_file_path, 'r') as file: 205 | csv_reader = csv.reader(file, delimiter='\t') 206 | print('=' * 89 + '\n', ' ' * 35, 'Available locales', ' ' * 35, '\n' + '=' * 89 + '\n') 207 | print('{0:<30}{1:<20}{2}'.format(*['Locale', 'Code set', 'Description'])) 208 | print('-' * 89) 209 | for row in csv_reader: 210 | print('{0:<30}{1:<20}{2}'.format(*row)) 211 | 212 | 213 | def set_size_cm( 214 | width: float, 215 | height: float = None 216 | ): 217 | if height is None: 218 | height = width 219 | 220 | cm2in = 1 / 2.54 221 | plt.rcParams['figure.figsize'] = (width * cm2in, height * cm2in) 222 | 223 | 224 | def set_legend( 225 | ax: matplotlib.axes.Axes, 226 | plot_tpl: Tuple[matplotlib.artist.Artist], 227 | label_tpl: Tuple[str], 228 | loc: str = 'lower left', 229 | outside_plot: bool = False, 230 | handle_scale_factor: float = 5. 231 | ): 232 | if outside_plot: 233 | if 'right' in loc: 234 | horizontal_anchor = 1.04 235 | loc = loc.replace('right', 'left') 236 | elif 'left' in loc: 237 | horizontal_anchor = 0.94 238 | loc = loc.replace('left', 'right') 239 | else: 240 | horizontal_anchor = 0.5 241 | 242 | if 'upper' in loc: 243 | vertical_anchor = 1. 244 | elif 'lower' in loc: 245 | vertical_anchor = 0. 246 | else: 247 | vertical_anchor = 0.5 248 | 249 | lgnd = ax.legend( 250 | plot_tpl, 251 | label_tpl, 252 | scatterpoints=1, 253 | loc=loc, 254 | bbox_to_anchor=(horizontal_anchor, vertical_anchor) 255 | ) 256 | else: 257 | lgnd = ax.legend( 258 | plot_tpl, 259 | label_tpl, 260 | scatterpoints=1, 261 | loc=loc, 262 | ) 263 | 264 | for lgnd_handle in lgnd.legendHandles: 265 | lgnd_handle._sizes = [handle_scale_factor] 266 | 267 | 268 | def get_color_lst( 269 | color_no: int, 270 | seaborn_color_map: str = 'cubehelix', 271 | colorful: bool = False 272 | ) -> List[str]: 273 | if color_no == 0 or not isinstance(color_no, int): 274 | raise SciplotException("Invalid number of colors: '" + str(color_no) + "'") 275 | 276 | if color_no > 4 and colorful: 277 | color_lst = sns.color_palette(seaborn_color_map, color_no).as_hex() 278 | elif color_no == 1 and not dark_mode: 279 | color_lst = ['#000000'] 280 | elif color_no == 1 and dark_mode: 281 | color_lst = ['#FFFFFF'] 282 | elif not colorful and dark_mode: 283 | color_lst = sns.color_palette(seaborn_color_map, color_no).as_hex()[:-1] + ['#FFFFFF'] 284 | else: 285 | color_lst = ['#000000'] + sns.color_palette(seaborn_color_map, color_no).as_hex()[:-1] 286 | 287 | return color_lst 288 | 289 | 290 | def save_time_stamped_figure( 291 | plot_file_name: str, # filnamn/filsökväg med eller utan ändelse, t.ex. .png eller .pdf 292 | save_directory: str = '', # valfri uppdelning i filnamn och mappsökväg 293 | file_type: str = 'png' # filtyp 294 | ): 295 | time_stamp = datetime.today().strftime('%Y-%m-%dT%H.%M') 296 | if 'png' in plot_file_name: 297 | plot_file_name = str(re.sub(r'\.png$', '', plot_file_name)) 298 | elif 'pdf' in plot_file_name: 299 | plot_file_name = str(re.sub(r'\.pdf$', '', plot_file_name)) 300 | 301 | if save_directory == '': 302 | plot_file_path = plot_file_name + '_' + time_stamp + '.' + file_type 303 | else: 304 | plot_file_path = os.path.join( 305 | save_directory, 306 | plot_file_name + '_' + time_stamp + '.' + file_type 307 | ) 308 | 309 | plt.savefig(plot_file_path, bbox_inches='tight', pad_inches=0.04) 310 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sciplot 2 | 3 | [](https://pypi.org/project/sciplot) 4 | [](https://github.com/andreasfuhr/sciplot) 5 | 6 | *Format Matplotlib scientific plots* 7 | 8 | *Sciplot* is a Python package that formats scientific plots created with Matplotlib in a 9 | user-friendly, yet highly customizable way. 10 | It makes typesetting in LaTeX possible and comes with several methods that makes plotting more 11 | straightforward and less cluttered, without sacrificing full control over plot settings. 12 | 13 | Two examples of plots created with Sciplot: 14 | 15 | example_plot 16 | example_plot 17 | 18 | The Sciplot package was developed by [Andreas Führ](https://www.linkedin.com/in/fuhrandreas/) in May 2021. 19 | 20 | ## Installation and getting started 21 | 22 | To install the latest release from PyPI, use the following command: 23 | 24 | ```bash 25 | pip install sciplot 26 | ``` 27 | 28 | To install the latest commit, please use: 29 | 30 | ```bash 31 | pip install git+https://github.com/andreasfuhr/sciplot.git 32 | ``` 33 | 34 |

35 | Formatting plots in Matplotlib is based on a functional `with`-statement context. A MWE can be demonstrated as follows: 36 | 37 | ```python 38 | import matplotlib.pyplot as plt 39 | import numpy as np 40 | import sciplot 41 | 42 | x = np.arange(0, 2 * np.pi, 1e-2) 43 | y1 = np.sin(2 * x + np.pi) 44 | y2 = np.cos(2 * x + np.pi) 45 | 46 | sciplot.set_size_cm(5) # Alternatively, set figure size with Matplotlib directly 47 | 48 | with sciplot.style(): 49 | plt.plot(x, y1, x, y2) 50 | plt.xticks( 51 | np.linspace(0, 2 * np.pi, 5), 52 | ['$0$', r'$\frac{\pi}{2}$', r'$\pi$', r'$\frac{3\pi}{2}$', r'$2\pi$'] 53 | ) 54 | plt.show() 55 | ``` 56 | 57 | This produces the following output: 58 | 59 | example_plot 60 | 61 | ## Overview 62 | 63 | ### Key Features 64 | 65 | * User-friendly. A *style context manager* is used for all Matplotlib related user code and can be passed several 66 | themes and arguments to alter the look of the plot, such as: 67 | * LaTeX typesetting 68 | * serif or sans serif font 69 | * dark mode 70 | * [locale](https://docs.oracle.com/cd/E23824_01/html/E26033/glset.html) string (for correct decimal 71 | separator etc.) 72 | * Implements LaTeX kernel for typesetting plots. A versatile LaTeX preamble is included that is specifically 73 | created and optionally editable for mathematics- and physics-oriented papers, theses and presentations. Both the 74 | [siunitx](https://ctan.org/pkg/siunitx) and [physics](https://www.ctan.org/pkg/physics) LaTeX packages are included by 75 | default in the parameter settings. 76 | * Easy customization. Most settings have been moved to parameters files, which are imported to the context manager and 77 | configured with `matplotlibrc`. The **user is encouraged to edit** these accessible and highly readable YAML parameters 78 | files, or **create new theme-associated parameter files**, whom are found with the `sciplot.get_paramters_dir()` 79 | method. 80 | * Includes a set of useful methods relevant during plotting: 81 | * `sciplot.set_size_cm()` for setting figure sizes in centimeters 82 | * `sciplot.set_legend()` for customizing the content and position of plot legends 83 | * `sciplot.get_color_lst()` for extracting a list of colors of specified length and from a given Seaborn colormap 84 | * `sciplot.save_time_stamped_figure` for saving plots in an easy manner with time stamped file names 85 | 86 | ### Disadvantages 87 | 88 | * Slow. LaTeX typesetting, turned on by default, can take quite some time to compile. Loading the parameters is however 89 | not known from experience to be time consuming. 90 | * Only compatible with Python 3.7 and later. The 3.3.4 version of Matplotlib fixes several bugs that directly solves 91 | some earlier issues with this package. 92 | 93 | It should be noted that although this package is in many ways similar to [[1]](#1), which is a recommended 94 | alternative approach, Sciplot has been independently developed and has a multitude of structural and functional 95 | differences. 96 | 97 | ## How to use Sciplot 98 | 99 | ### The style context and themes 100 | 101 | The `sciplot.style()` context manager is the core feature of Sciplot. It is a powerful and versetile tool for a 102 | complete control of the looks of plots created with Matplotlib. The context manager operates with two input arguments: 103 | `theme` and `locale_setting`. By default, creating plots within the style context 104 | 105 | ```python 106 | with sciplot.style(): 107 | ... 108 | ``` 109 | 110 | is equivalent to the following style context: 111 | 112 | ```python 113 | with sciplot.style(theme='default', locale_setting='sv_SE.UTF-8'): 114 | ... 115 | ``` 116 | 117 | #### Themes 118 | 119 | A handful of themes are bundled with Sciplot. The `theme` argument can be passed either a single theme as a *string* or 120 | a *list of theme strings*. Since all themes are not mutually exclusive w.r.t. Matplotlib settings, the themes are 121 | segmented such that Sciplot distinguishes which style settings are more important and becomes prioritized (higher 122 | number means lower priority): 123 | 124 | Priority | Theme | Description 125 | :------- | :--------------- | :---------- 126 | 0 | *Custom theme* | A theme entirely made by the user. This is done by creating a parameter file in the `sciplot.parameter` directory. A theme named **my_fabulous_theme** will for example extract parameter settings from a file named `my_fabulous_theme.yml`. 127 | 1 | ***alpha*** | Predefined, contentless user theme. Intended for editing by user. 128 | 2 | ***beta*** | Predefined, contentless user theme. Intended for editing by user. 129 | 3 | ***gamma*** | Predefined, contentless user theme. Intended for editing by user. 130 | 4 | ***no-latex*** | No local LaTeX kernel is used for typesetting. 131 | 5 | ***serif*** | *Computer Modern Roman* used as text and math font, with typesetting in LaTeX. 132 | 6 | ***sans-serif*** | *Computer Modern Roman Sans Serif* used as text and math font, with typesetting in LaTeX. 133 | 7 | ***dark*** | Uses Matplotlib's `dark_background` style and comes with a set of colours suitable for plotting against a black background. 134 | 8 | ***default*** | The default theme. Always active unless the ***clean*** "theme" is used. Uses LaTeX typesetting and *Computer Modern Roman Sans Serif* as text and math font. Initialises basic figure settings for linewidths, ticks, legends, font sizes, dpi, margins, etc. Also comes with the *cubehelix* colourmap [[2]](#2) as well as basic plot colours and styles. 135 | – | ***clean*** | Not technically a theme. Simpy inactivates the ***default*** theme. 136 | 137 | #### Locales 138 | 139 | The `locale_setting` argument lets the user determine the *locale* to be used in a plot, thereby determining a set of 140 | parameters that defines the user's language, region and other regionally based settings and whom are used by Matplotlib 141 | to alter the appearance of a plot. To see all available locales, one can call the `sciplot.get_available_locals` 142 | method for a console printout. 143 | 144 | #### Code example 145 | 146 | If a plot style with dark theme, LaTeX, a serif font (Computer Modern Roman) and local settings for the United States 147 | is requested, the style context should be initiated with 148 | 149 | ```python 150 | with sciplot.style(['dark', 'serif'], 'en_US'): 151 | ... 152 | ``` 153 | 154 | ## Future improvements 155 | 156 | The package is still in its infancy and is planned to be expanded in features and configurability. Here is a list of 157 | what is in the pipeline: 158 | * Documentation of source code 159 | * Instructions on how to install a local LaTeX distribution 160 | * Making it possible to choose LaTeX fonts. As of currently, *Computer Modern Roman* and *Computer Modern Roman Sans 161 | Serif* are the only two font options for both text and mathematical notation. 162 | * Include more example plots in documentation 163 | * Write instructions on how to use the package 164 | * Address potential issues with user defined themes and updating sciplot 165 | * Move sciplot methods not used by the user outside of `sciplot.main` 166 | 167 | ### Table of proposed themes not yet implemented 168 | 169 | Name of theme | Priority | Background color | Font | Seaborn colormap | Figure size 170 | :--------------------------------------- | :------- | :--------------- | :--------------------------- | :--------------- | :-------------------------------- 171 | ***antique*** | low | white | Garamond | *TBD* | - 172 | ***ieee_column*** | medium | white | ?[1](#f1) | *TBD* | 88 mm[2](#f2) 173 | ***ieee_page*** | low | white | ?[1](#f1) | *TBD* | 181 mm[2](#f2) 174 | ***grid*** | high 175 | 176 | 1: One of the following Open Type fonts are suggested to be used: Times New Roman, Helvetica, Arial, 177 | Cambria or Symbol [[3]](#3). 178 | 179 | 2: See [[3]](#3) for a description of sizes that graphics should be. 180 | 181 | ## Citing Sciplot 182 | 183 | To cite this Python package, please use the following BibTeX citation: 184 | 185 | ```tex 186 | @article{Sciplot, 187 | author = {Andreas H. Führ}, 188 | title = {{andreasfuhr/sciplot}}, 189 | month = May, 190 | year = 2021, 191 | version = {0.8.1}, 192 | url = {https://github.com/andreasfuhr/sciplot} 193 | } 194 | ``` 195 | 196 | Note that under the current license, citing this package is not necessary. The creator will however be happy and 197 | thankful for any recognition. 198 | 199 | ## References 200 | 201 | [1] 202 | J.D. Garrett and H. Peng, 203 | *garrettj403/SciencePlots*, 204 | ver. 1.0.7. 205 | Zenodo, 206 | Feb. 2021. 207 | \[Online]. 208 | doi: [10.5281/zenodo.4106649](http://doi.org/10.5281/zenodo.4106649) 209 | 210 | [2] 211 | D.A. Green, 212 | "A colour scheme for the display of astronomical intensity images," 213 | in *Bulletin of the Astronomical Society of India*, vol. 39, pp. 289–295, 2011. 214 | \[Online]. 215 | Available: [arXiv:1108.5083](https://arxiv.org/abs/1108.5083). 216 | 217 | [3] 218 | "Preparation of papers for IEEE Transactions and Journals (December 2013)," 219 | in IEEE Transactions on Consumer Electronics, 220 | vol. 63, 221 | no. 1, 222 | pp. c3-c3, 223 | February 2017, 224 | doi: [10.1109/TCE.2017.7932035](http://doi.org/10.1109/TCE.2017.7932035) 225 | -------------------------------------------------------------------------------- /sciplot/parameters/locales.csv: -------------------------------------------------------------------------------- 1 | C US-ASCII C,POSIX 2 | POSIX US-ASCII C,POSIX 3 | af_ZA.UTF-8 UTF-8 Afrikaans,SouthAfrica 4 | ar_AE.UTF-8 UTF-8 Arabic,UnitedArabEmirates 5 | ar_BH.UTF-8 UTF-8 Arabic,Bahrain 6 | ar_DZ.UTF-8 UTF-8 Arabic,Algeria 7 | ar_EG.UTF-8 UTF-8 Arabic,Egypt 8 | ar_IQ.UTF-8 UTF-8 Arabic,Iraq 9 | ar_JO.UTF-8 UTF-8 Arabic,Jordan 10 | ar_KW.UTF-8 UTF-8 Arabic,Kuwait 11 | ar_LY.UTF-8 UTF-8 Arabic,Libya 12 | ar_MA.UTF-8 UTF-8 Arabic,Morocco 13 | ar_OM.UTF-8 UTF-8 Arabic,Oman 14 | ar_QA.UTF-8 UTF-8 Arabic,Qatar 15 | ar_SA.UTF-8 UTF-8 Arabic,SaudiArabia 16 | ar_TN.UTF-8 UTF-8 Arabic,Tunisia 17 | ar_YE.UTF-8 UTF-8 Arabic,Yemen 18 | as_IN.UTF-8 UTF-8 Assamese,India 19 | az_AZ.UTF-8 UTF-8 Azerbaijani,Azerbaijan 20 | be_BY.UTF-8 UTF-8 Belarusian,Belarus 21 | bg_BG.UTF-8 UTF-8 Bulgarian,Bulgaria 22 | bn_IN.UTF-8 UTF-8 Bengali,India 23 | bs_BA.UTF-8 UTF-8 Bosnian,BosniaandHerzegovina 24 | ca_ES.UTF-8 UTF-8 Catalan,Spain 25 | cs_CZ.UTF-8 UTF-8 Czech,CzechRepublic 26 | da_DK.UTF-8 UTF-8 Danish,Denmark 27 | de_AT.UTF-8 UTF-8 German,Austria 28 | de_BE.UTF-8 UTF-8 German,Belgium 29 | de_CH.UTF-8 UTF-8 German,Switzerland 30 | de_DE.UTF-8 UTF-8 German,Germany 31 | de_LI.UTF-8 UTF-8 German,Liechtenstein 32 | de_LU.UTF-8 UTF-8 German,Luxembourg 33 | el_CY.UTF-8 UTF-8 Greek,Cyprus 34 | el_GR.UTF-8 UTF-8 Greek,Greece 35 | en_AU.UTF-8 UTF-8 English,Australia 36 | en_BW.UTF-8 UTF-8 English,Botswana 37 | en_CA.UTF-8 UTF-8 English,Canada 38 | en_GB.UTF-8 UTF-8 English,UnitedKingdom 39 | en_HK.UTF-8 UTF-8 English,HongKongSARChina 40 | en_IE.UTF-8 UTF-8 English,Ireland 41 | en_IN.UTF-8 UTF-8 English,India 42 | en_MT.UTF-8 UTF-8 English,Malta 43 | en_NZ.UTF-8 UTF-8 English,NewZealand 44 | en_PH.UTF-8 UTF-8 English,Philippines 45 | en_SG.UTF-8 UTF-8 English,Singapore 46 | en_US.UTF-8 UTF-8 English,U.S.A. 47 | en_ZW.UTF-8 UTF-8 English,Zimbabwe 48 | es_AR.UTF-8 UTF-8 Spanish,Argentina 49 | es_BO.UTF-8 UTF-8 Spanish,Bolivia 50 | es_CL.UTF-8 UTF-8 Spanish,Chile 51 | es_CO.UTF-8 UTF-8 Spanish,Colombia 52 | es_CR.UTF-8 UTF-8 Spanish,CostaRica 53 | es_DO.UTF-8 UTF-8 Spanish,DominicanRepublic 54 | es_EC.UTF-8 UTF-8 Spanish,Ecuador 55 | es_ES.UTF-8 UTF-8 Spanish,Spain 56 | es_GT.UTF-8 UTF-8 Spanish,Guatemala 57 | es_HN.UTF-8 UTF-8 Spanish,Honduras 58 | es_MX.UTF-8 UTF-8 Spanish,Mexico 59 | es_NI.UTF-8 UTF-8 Spanish,Nicaragua 60 | es_PA.UTF-8 UTF-8 Spanish,Panama 61 | es_PE.UTF-8 UTF-8 Spanish,Peru 62 | es_PR.UTF-8 UTF-8 Spanish,PuertoRico 63 | es_PY.UTF-8 UTF-8 Spanish,Paraguay 64 | es_SV.UTF-8 UTF-8 Spanish,ElSalvador 65 | es_US.UTF-8 UTF-8 Spanish,U.S.A. 66 | es_UY.UTF-8 UTF-8 Spanish,Uruguay 67 | es_VE.UTF-8 UTF-8 Spanish,Venezuela 68 | et_EE.UTF-8 UTF-8 Estonian,Estonia 69 | fi_FI.UTF-8 UTF-8 Finnish,Finland 70 | fr_BE.UTF-8 UTF-8 French,Belgium 71 | fr_CA.UTF-8 UTF-8 French,Canada 72 | fr_CH.UTF-8 UTF-8 French,Switzerland 73 | fr_FR.UTF-8 UTF-8 French,France 74 | fr_LU.UTF-8 UTF-8 French,Luxembourg 75 | gu_IN.UTF-8 UTF-8 Gujarati,India 76 | he_IL.UTF-8 UTF-8 Hebrew,Israel 77 | hi_IN.UTF-8 UTF-8 Hindi,India 78 | hr_HR.UTF-8 UTF-8 Croatian,Croatia 79 | hu_HU.UTF-8 UTF-8 Hungarian,Hungary 80 | hy_AM.UTF-8 UTF-8 Armenian,Armenia 81 | id_ID.UTF-8 UTF-8 Indonesian,Indonesia 82 | is_IS.UTF-8 UTF-8 Icelandic,Iceland 83 | it_CH.UTF-8 UTF-8 Italian,Switzerland 84 | it_IT.UTF-8 UTF-8 Italian,Italy 85 | ja_JP.UTF-8 UTF-8 Japanese,Japan 86 | ka_GE.UTF-8 UTF-8 Georgian,Georgia 87 | kk_KZ.UTF-8 UTF-8 Kazakh,Kazakhstan 88 | kn_IN.UTF-8 UTF-8 Kannada,India 89 | ko_KR.UTF-8 UTF-8 Korean,Korea 90 | ks_IN.UTF-8 UTF-8 Kashmiri,India 91 | ku_TR.UTF-8 UTF-8 Kurdish,Turkey 92 | ku_TR.UTF-8@sorani UTF-8 Kurdish(Sorani),Turkey 93 | ky_KG.UTF-8 UTF-8 Kirghiz,Kyrgyzstan 94 | lt_LT.UTF-8 UTF-8 Lithuanian,Lithuania 95 | lv_LV.UTF-8 UTF-8 Latvian,Latvia 96 | mk_MK.UTF-8 UTF-8 Macedonian,Macedonia 97 | ml_IN.UTF-8 UTF-8 Malayalam,India 98 | mr_IN.UTF-8 UTF-8 Marathi,India 99 | ms_MY.UTF-8 UTF-8 Malay,Malaysia 100 | mt_MT.UTF-8 UTF-8 Maltese,Malta 101 | nb_NO.UTF-8 UTF-8 Bokmal,Norway 102 | nl_BE.UTF-8 UTF-8 Dutch,Belgium 103 | nl_NL.UTF-8 UTF-8 Dutch,Netherlands 104 | nn_NO.UTF-8 UTF-8 Nynorsk,Norway 105 | or_IN.UTF-8 UTF-8 Oriya,India 106 | pa_IN.UTF-8 UTF-8 Punjabi,India 107 | pl_PL.UTF-8 UTF-8 Polish,Poland 108 | pt_BR.UTF-8 UTF-8 Portuguese,Brazil 109 | pt_PT.UTF-8 UTF-8 Portuguese,Portugal 110 | ro_RO.UTF-8 UTF-8 Romanian,Romania 111 | ru_RU.UTF-8 UTF-8 Russian,Russia 112 | ru_UA.UTF-8 UTF-8 Russian,Ukraine 113 | sa_IN.UTF-8 UTF-8 Sanskrit,India 114 | sk_SK.UTF-8 UTF-8 Slovak,Slovakia 115 | sl_SI.UTF-8 UTF-8 Slovenian,Slovenia 116 | sq_AL.UTF-8 UTF-8 Albanian,Albania 117 | sr_ME.UTF-8 UTF-8 Serbian,Montenegro 118 | sr_ME.UTF-8@latin UTF-8 Serbian,Montenegro(Latin) 119 | sr_RS.UTF-8 UTF-8 Serbian,Serbia 120 | sr_RS.UTF-8@latin UTF-8 Serbian,Serbia(Latin) 121 | sv_SE.UTF-8 UTF-8 Swedish,Sweden 122 | ta_IN.UTF-8 UTF-8 Tamil,India 123 | te_IN.UTF-8 UTF-8 Telugu,India 124 | th_TH.UTF-8 UTF-8 Thai,Thailand 125 | tr_TR.UTF-8 UTF-8 Turkish,Turkey 126 | uk_UA.UTF-8 UTF-8 Ukrainian,Ukraine 127 | vi_VN.UTF-8 UTF-8 Vietnamese,Vietnam 128 | zh_CN.UTF-8 UTF-8 SimplifiedChinese,China 129 | zh_HK.UTF-8 UTF-8 TraditionalChinese,HongKongSARChina 130 | zh_SG.UTF-8 UTF-8 Chinese,Singapore 131 | zh_TW.UTF-8 UTF-8 TraditionalChinese,Taiwan 132 | ar_EG.ISO8859-6 ISO8859-6 Arabic,Egypt 133 | bg_BG.ISO8859-5 ISO8859-5 Bulgarian,Bulgaria 134 | bs_BA.ISO8859-2 ISO8859-2 Bosnian,BosniaandHerzegovina 135 | ca_ES.ISO8859-1 ISO8859-1 Catalan,Spain 136 | ca_ES.ISO8859-15 ISO8859-15 Catalan,Spain 137 | cs_CZ.ISO8859-2 ISO8859-2 Czech,CzechRepublic 138 | CZ.UTF-8@euro UTF-8 Czech,CzechRepublic(Euro) 139 | da_DK.ISO8859-1 ISO8859-1 Danish,Denmark 140 | da_DK.ISO8859-15 ISO8859-15 Danish,Denmark 141 | da_DK.ISO8859-15@euro ISO8859-15 Danish,Denmark(Euro) 142 | de_AT.ISO8859-1 ISO8859-1 German,Austria 143 | de_AT.ISO8859-15 ISO8859-15 German,Austria 144 | de_CH.ISO8859-1 ISO8859-1 German,Switzerland 145 | de_DE.ISO8859-1 ISO8859-1 German,Germany 146 | de_DE.ISO8859-15 ISO8859-15 German,Germany 147 | el_GR.ISO8859-7 ISO8859-7 Greek,Greece 148 | en_AU.ISO8859-1 ISO8859-1 English,Australia 149 | en_CA.ISO8859-1 ISO8859-1 English,Canada 150 | en_GB.ISO8859-1 ISO8859-1 English,UnitedKingdom 151 | en_GB.ISO8859-15 ISO8859-15 English,UnitedKingdom 152 | en_GB.ISO8859-15@euro ISO8859-15 English,UnitedKingdom(Euro) 153 | en_IE.ISO8859-1 ISO8859-1 English,Ireland 154 | en_IE.ISO8859-15 ISO8859-15 English,Ireland 155 | en_NZ.ISO8859-1 ISO8859-1 English,NewZealand 156 | en_US.ISO8859-1 ISO8859-1 English,U.S.A. 157 | en_US.ISO8859-15 ISO8859-15 English,U.S.A. 158 | en_US.ISO8859-15@euro ISO8859-15 English,U.S.A.(Euro) 159 | es_AR.ISO8859-1 ISO8859-1 Spanish,Argentina 160 | es_BO.ISO8859-1 ISO8859-1 Spanish,Bolivia 161 | es_CL.ISO8859-1 ISO8859-1 Spanish,Chile 162 | es_CO.ISO8859-1 ISO8859-1 Spanish,Colombia 163 | es_CR.ISO8859-1 ISO8859-1 Spanish,CostaRica 164 | es_EC.ISO8859-1 ISO8859-1 Spanish,Ecuador 165 | es_ES.ISO8859-1 ISO8859-1 Spanish,Spain 166 | es_ES.ISO8859-15 ISO8859-15 Spanish,Spain 167 | es_GT.ISO8859-1 ISO8859-1 Spanish,Guatemala 168 | es_MX.ISO8859-1 ISO8859-1 Spanish,Mexico 169 | es_NI.ISO8859-1 ISO8859-1 Spanish,Nicaragua 170 | es_PA.ISO8859-1 ISO8859-1 Spanish,Panama 171 | es_PE.ISO8859-1 ISO8859-1 Spanish,Peru 172 | es_PY.ISO8859-1 ISO8859-1 Spanish,Paraguay 173 | es_SV.ISO8859-1 ISO8859-1 Spanish,ElSalvador 174 | es_UY.ISO8859-1 ISO8859-1 Spanish,Uruguay 175 | es_VE.ISO8859-1 ISO8859-1 Spanish,Venezuela 176 | et_EE.ISO8859-15 ISO8859-15 Estonian,Estonia 177 | fi_FI.ISO8859-1 ISO8859-1 Finnish,Finland 178 | fi_FI.ISO8859-15 ISO8859-15 Finnish,Finland 179 | fr_BE.ISO8859-1 ISO8859-1 French,Belgium 180 | fr_BE.ISO8859-15 ISO8859-15 French,Belgium 181 | fr_CA.ISO8859-1 ISO8859-1 French,Canada 182 | fr_CH.ISO8859-1 ISO8859-1 French,Switzerland 183 | fr_FR.ISO8859-1 ISO8859-1 French,France 184 | fr_FR.ISO8859-15 ISO8859-15 French,France 185 | he_IL.ISO8859-8 ISO8859-8 Hebrew,Israel 186 | hr_HR.ISO8859-2 ISO8859-2 Croatian,Croatia 187 | hu_HU.ISO8859-2 ISO8859-2 Hungarian,Hungary 188 | is_IS.ISO8859-1 ISO8859-1 Icelandic,Iceland 189 | it_IT.ISO8859-1 ISO8859-1 Italian,Italy 190 | it_IT.ISO8859-15 ISO8859-15 Italian,Italy 191 | ja_JP.PCK PCK Japanese,Japan(PCKanjicode,aka.Shift-JIS) 192 | ja_JP.eucJP EUC-JP JapaneseEUCenvironment.ComplianttoUI-OSFJapaneseEnvironmentImplementationAgreementVersion1.1 193 | ko_KR.EUC KSX1001 Korean,Korea 194 | ko_KR.EUC@dict KSX1001 Korean,Korea(dict) 195 | ko_KR.UTF-8@dict UTF-8 Korean,Korea(dict) 196 | lt_LT.ISO8859-13 ISO8859-13 Lithuanian,Lithuania 197 | lv_LV.ISO8859-13 ISO8859-13 Latvian,Latvia 198 | mk_MK.ISO8859-5 ISO8859-5 Macedonian,Macedonia 199 | nb_NO.ISO8859-1 ISO8859-1 NorwegianBokmal,Norway 200 | nl_BE.ISO8859-1 ISO8859-1 Dutch,Belgium 201 | nl_BE.ISO8859-15 ISO8859-15 Dutch,Belgium 202 | nl_NL.ISO8859-1 ISO8859-1 Dutch,Netherlands 203 | nl_NL.ISO8859-15 ISO8859-15 Dutch,Netherlands 204 | nn_NO.ISO8859-1 ISO8859-1 NorwegianNynorsk,Norway 205 | pl_PL.ISO8859-2 ISO8859-2 Polish,Poland 206 | pt_BR.ISO8859-1 ISO8859-1 Portuguese,Brazil 207 | pt_PT.ISO8859-1 ISO8859-1 Portuguese,Portugal 208 | pt_PT.ISO8859-15 ISO8859-15 Portuguese,Portugal 209 | ro_RO.ISO8859-2 ISO8859-2 Romanian,Romania 210 | ru_RU.ANSI1251 ANSI1251 Russian,Russia 211 | ru_RU.ISO8859-5 ISO8859-5 Russian,Russia 212 | ru_RU.KOI8-R KOI8-R Russian,Russia 213 | sk_SK.ISO8859-2 ISO8859-2 Slovak,Slovakia 214 | sl_SI.ISO8859-2 ISO8859-2 Slovenian,Slovenia 215 | sq_AL.ISO8859-2 ISO8859-2 Albanian,Albania 216 | sr_ME.ISO8859-5 ISO8859-5 Serbian,Montenegro 217 | sv_SE.ISO8859-1 ISO8859-1 Swedish,Sweden 218 | sv_SE.ISO8859-15 ISO8859-15 Swedish,Sweden 219 | sv_SE.ISO8859-15@euro ISO8859-15 Swedish,Sweden(Euro) 220 | sv_SE.UTF-8@euro UTF-8 Swedish,Sweden(Euro) 221 | th_TH.TIS620 TIS-620 Thai,Thailand 222 | tr_TR.ISO8859-9 ISO8859-9 Turkish,Turkey 223 | zh_CN.EUC GB2312 SimplifiedChinese,China 224 | zh_CN.EUC@pinyin GB2312 SimplifiedChinese,China(pinyin) 225 | zh_CN.EUC@radical GB2312 SimplifiedChinese,China(radical) 226 | zh_CN.EUC@stroke GB2312 SimplifiedChinese,China(stroke) 227 | zh_CN.GB18030 GB18030 SimplifiedChinese,China 228 | zh_CN.GB18030@pinyin GB18030 SimplifiedChinese,China(pinyin) 229 | zh_CN.GB18030@radical GB18030 SimplifiedChinese,China(radical) 230 | zh_CN.GB18030@stroke GB18030 SimplifiedChinese,China(stroke) 231 | zh_CN.GBK GBK SimplifiedChinese,China 232 | zh_CN.GBK@pinyin GBK SimplifiedChinese,China(pinyin) 233 | zh_CN.GBK@radical GBK SimplifiedChinese,China(radical) 234 | zh_CN.GBK@stroke GBK SimplifiedChinese,China(stroke) 235 | zh_CN.UTF-8@pinyin UTF-8 SimplifiedChinese,China(pinyin) 236 | zh_CN.UTF-8@radical UTF-8 SimplifiedChinese,China(radical) 237 | zh_CN.UTF-8@stroke UTF-8 SimplifiedChinese,China(stroke) 238 | zh_HK.BIG5HK BIG5-HKSCS TraditionalChinese,HongKongSARChina 239 | zh_HK.BIG5HK@radical BIG5-HKSCS TraditionalChinese,HongKongSARChina(radical) 240 | zh_HK.BIG5HK@stroke BIG5-HKSCS TraditionalChinese,HongKongSARChina(stroke) 241 | zh_HK.UTF-8@radical UTF-8 TraditionalChinese,HongKongSARChina(radical) 242 | zh_HK.UTF-8@stroke UTF-8 TraditionalChinese,HongKongSARChina(stroke) 243 | zh_TW.BIG5 BIG5 TraditionalChinese,Taiwan 244 | zh_TW.BIG5@pinyin BIG5 TraditionalChinese,Taiwan(pinyin) 245 | zh_TW.BIG5@radical BIG5 TraditionalChinese,Taiwan(radical) 246 | zh_TW.BIG5@stroke BIG5 TraditionalChinese,Taiwan(stroke) 247 | zh_TW.BIG5@zhuyin BIG5 TraditionalChinese,Taiwan(zhuyin) 248 | zh_TW.EUC CNS11643-1992 TraditionalChinese,Taiwan 249 | zh_TW.EUC@pinyin CNS11643 TraditionalChinese,Taiwan(pinyin) 250 | zh_TW.EUC@radical CNS11643 TraditionalChinese,Taiwan(radical) 251 | zh_TW.EUC@stroke CNS11643 TraditionalChinese,Taiwan(stroke) 252 | zh_TW.EUC@zhuyin CNS11643 TraditionalChinese,Taiwan(zhuyin) 253 | zh_TW.UTF-8@pinyin UTF-8 TraditionalChinese,Taiwan(pinyin) 254 | zh_TW.UTF-8@radical UTF-8 TraditionalChinese,Taiwan(radical) 255 | zh_TW.UTF-8@stroke UTF-8 TraditionalChinese,Taiwan(stroke) 256 | zh_TW.UTF-8@zhuyin UTF-8 TraditionalChinese,Taiwan(zhuyin) --------------------------------------------------------------------------------