├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── MANIFEST.in ├── README.md ├── docs ├── mpl_default.png ├── publib_article.png ├── publib_origin.png ├── publib_origin_latex.png └── publib_poster_origin.png ├── publib ├── __init__.py ├── __version__.txt ├── main.py ├── stylelib │ ├── B&W.mplstyle │ ├── article.mplstyle │ ├── article_s.mplstyle │ ├── basic.mplstyle │ ├── latex.mplstyle │ ├── origin.mplstyle │ ├── poster.mplstyle │ ├── small.mplstyle │ └── talk.mplstyle ├── test │ ├── __init__.py │ ├── test_functions.py │ └── test_tools.py └── tools │ ├── __init__.py │ ├── colors.py │ ├── fix.py │ └── tools.py ├── register.py ├── setup.py └── setuptips.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled python modules. 2 | *.pyc 3 | 4 | # Setuptools distribution folder. 5 | /dist/ 6 | 7 | # Python egg metadata, regenerated from source files by setuptools. 8 | /*.egg-info 9 | 10 | README.rst 11 | 12 | /build/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | # We don't actually use the Travis Python, but this keeps it organized. 4 | - "2.7" 5 | - "3.6" 6 | install: 7 | - sudo apt-get update 8 | # Install Anaconda 9 | # We do this conditionally because it saves us some downloading if the 10 | # version is the same. 11 | - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then 12 | wget https://repo.anaconda.com/miniconda/Miniconda2-latest-Linux-x86_64.sh -O miniconda.sh; 13 | else 14 | wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; 15 | fi 16 | - bash miniconda.sh -b -p $HOME/miniconda 17 | - export PATH="$HOME/miniconda/bin:$PATH" 18 | - hash -r 19 | - conda config --set always_yes yes --set changeps1 no 20 | - conda update -q conda 21 | # Useful for debugging any issues with conda 22 | - conda info -a 23 | 24 | # Create conda environment 25 | - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION pytest numpy matplotlib 26 | - source activate test-environment 27 | - pip install codecov pytest-cov 28 | - python setup.py install 29 | 30 | script: 31 | # Your test script goes here 32 | - echo ">>> Running tests" 33 | # use XVFB to have headless display port, and still run the Matplotlib tests. 34 | - xvfb-run pytest --cov=./ 35 | 36 | # safelist 37 | branches: 38 | only: 39 | - master 40 | - develop 41 | 42 | 43 | after_success: 44 | - codecov -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010-2018 Google, Inc. http://angularjs.org 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include publib/stylelib/*.mplstyle 3 | include LICENSE 4 | include publib/__version__.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![PyPI version](https://badge.fury.io/py/publib.svg)](https://badge.fury.io/py/publib) 2 | [![Tests](https://img.shields.io/travis/erwanp/publib.svg)](https://travis-ci.org/erwanp/publib) 3 | [![Code coverage](https://codecov.io/gh/erwanp/publib/branch/master/graph/badge.svg)](https://codecov.io/gh/erwanp/publib) 4 | 5 | # Publib 6 | 7 | ## Description 8 | 9 | Produce publication-level quality images on top of Matplotlib, with a 10 | simple call to a couple functions at the start and end of your script. 11 | 12 | [Project GitHub page](https://github.com/erwanp/publib) 13 | 14 | For similar librairies, see the [References section](https://github.com/erwanp/publib#references). 15 | 16 | ## Install 17 | 18 | ``` 19 | pip install publib 20 | ``` 21 | 22 | ## Use 23 | 24 | At the beginning of the script, call: 25 | 26 | ``` {.sourceCode .python} 27 | set_style() 28 | ``` 29 | 30 | After each new axe is plotted, call: 31 | 32 | ``` {.sourceCode .python} 33 | fix_style() 34 | ``` 35 | 36 | Note that importing publib will already load the basic style. 37 | 38 | A few more styles (`'poster'`, `'article'`, etc.) can be selected with the 39 | function `set_style()` 40 | 41 | Because some matplotlib parameters cannot be changed before the lines 42 | are plotted, they are called through the function `fix_style()` which: 43 | 44 | - changes the minor ticks 45 | 46 | - remove the spines 47 | 48 | - turn the legend draggable by default 49 | 50 | ## Examples 51 | 52 | ``` {.sourceCode .python} 53 | import numpy as np 54 | import matplotlib.pyplot as plt 55 | import matplotlib as mpl 56 | ``` 57 | 58 | A default Matplotlib plot: 59 | 60 | ``` {.sourceCode .python} 61 | mpl.rcdefaults() 62 | 63 | x = np.linspace(0,5,250) 64 | y = np.cos(x)**2+np.random.normal(scale=0.5,size=len(x)) 65 | yav = np.cos(x)**2 66 | plt.figure() 67 | ax = plt.subplot() 68 | ax.plot(x,y,'o',label='normal distribution') 69 | ax.plot(x,yav,zorder=-1,label='average') 70 | plt.xlabel(r'$x$') 71 | plt.ylabel(r'$\cos^2 x$+noise') 72 | plt.title('matplotlib') 73 | plt.legend(loc='upper left') 74 | plt.ylim((-1.5,3.5)) 75 | plt.show() 76 | plt.savefig('mpl_default.png') 77 | ``` 78 | 79 | ![mpl_defaults.png](https://github.com/erwanp/publib/blob/master/docs/mpl_default.png) 80 | 81 | And now the same code with the two new lines calling the 82 | publib functions 83 | 84 | ``` {.sourceCode .python} 85 | from publib import set_style, fix_style 86 | set_style('article') # before the first plot 87 | 88 | x = np.linspace(0,5,250) 89 | y = np.cos(x)**2+np.random.normal(scale=0.5,size=len(x)) 90 | yav = np.cos(x)**2 91 | plt.figure() 92 | ax = plt.subplot() 93 | ax.plot(x,y,'o',label='normal distribution') 94 | ax.plot(x,yav,zorder=-1,label='average') 95 | plt.xlabel(r'$x$') 96 | plt.ylabel(r'$\cos^2 x$+noise') 97 | plt.title('article') 98 | plt.legend(loc='upper left') 99 | plt.ylim((-1.5,3.5)) 100 | 101 | fix_style('article') # after the axe has been created 102 | 103 | plt.show() 104 | plt.savefig('publib_article.png') 105 | ``` 106 | 107 | ![publib_article.png](https://github.com/erwanp/publib/blob/master/docs/publib_article.png) 108 | 109 | The [OriginPro](https://www.originlab.com/Origin) style: 110 | 111 | ``` 112 | set_style('origin') 113 | 114 | ... 115 | 116 | fix_style('origin') 117 | ``` 118 | 119 | ![publib_origin.png](https://github.com/erwanp/publib/blob/master/docs/publib_origin.png) 120 | 121 | A combination of styles: 122 | 123 | ``` 124 | set_style(['poster', 'origin']) 125 | 126 | ... 127 | 128 | fix_style(['poster', 'origin']) 129 | ``` 130 | 131 | ![publib_poster_origin.png](https://github.com/erwanp/publib/blob/master/docs/publib_poster_origin.png) 132 | 133 | Or, assuming you have the Latin Modern Math font installed: 134 | 135 | ``` 136 | set_style(['origin', 'latex']) 137 | 138 | ... 139 | 140 | fix_style(['origin', 'latex']) 141 | ``` 142 | 143 | ![publib_origin_latex.png](https://github.com/erwanp/publib/blob/master/docs/publib_origin_latex.png) 144 | 145 | 146 | 147 | 148 | 149 | Run the test() routines in `publib.test` for more examples. 150 | 151 | 152 | ## Tools 153 | 154 | The publib.tools module include independant functions to fix some common matplotlib bugs, 155 | or include extra features. They're usually glanced from somewhere on the web. Proper 156 | referencing is made in the function docstrings. 157 | 158 | See for instance: 159 | 160 | - `publib.tools.reset_defaults`: reset Matplotlib defaults 161 | 162 | - `publib.tools.regenerate_fonts`: rebuild Matplotlib font cache 163 | 164 | - `publib.tools.fix_bold_TimesNewRoman`: fix Times New Roman font appearing bold. See 165 | [StackOverflow](https://stackoverflow.com/questions/33955900/matplotlib-times-new-roman-appears-bold) 166 | 167 | - `publib.tools.keep_color`: apply the same color for the next graph to plot 168 | 169 | - `publib.tools.get_next_color`: see which color will be applied next in the color cycle state 170 | 171 | ``` 172 | plt.plot(...) 173 | keep_color() 174 | plt.plot(...) 175 | ``` 176 | 177 | - `publib.tools.list_font_names`: to list all fonts available in Python. 178 | 179 | 180 | See [tools.py](https://github.com/erwanp/publib/blob/master/publib/tools/__init__.py) 181 | for more details 182 | 183 | ## Changes 184 | 185 | - 0.2.2: added tools 186 | 187 | - 0.1.9: added talk and OriginPro style 188 | 189 | - 0.1.7 : default fonts to Times in article 190 | 191 | ## References 192 | 193 | Some other interesting packages to make nice graphs in Matplotlib. 194 | 195 | Add new features: 196 | 197 | - [pypdfplot](https://github.com/dcmvdbekerom/pypdfplot): embed the script within the pdf. One single file for the figure and the code! 198 | - [brokenaxes](https://github.com/bendichter/brokenaxes) 199 | - [matplotlib-tools](https://github.com/terranjp/matplotlib-tools): toolbar (ruler, etc.) 200 | 201 | Style based: 202 | 203 | - the Matplotlib default [style feature](http://matplotlib.org/users/style_sheets.html) 204 | - [seaborn](http://stanford.edu/~mwaskom/software/seaborn/) 205 | - [prettyplotlib](https://github.com/olgabot/prettyplotlib) 206 | - [garrettj403](https://github.com/garrettj403)'s matplotlib styles for [ThesisPlot](https://github.com/garrettj403/ThesisPlots) 207 | 208 | Tips and demos of Matplotlib: 209 | 210 | - [A great cheatsheet](https://nbviewer.jupyter.org/urls/gist.githubusercontent.com/Jwink3101/e6b57eba3beca4b05ec146d9e38fc839/raw/f486ca3dcad44c33fc4e7ddedc1f83b82c02b492/Matplotlib_Cheatsheet) 211 | by [Jwink3101](https://github.com/Jwink3101) 212 | -------------------------------------------------------------------------------- /docs/mpl_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erwanp/publib/57d784850315f03aaea30d9e3a290f5ff95bef77/docs/mpl_default.png -------------------------------------------------------------------------------- /docs/publib_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erwanp/publib/57d784850315f03aaea30d9e3a290f5ff95bef77/docs/publib_article.png -------------------------------------------------------------------------------- /docs/publib_origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erwanp/publib/57d784850315f03aaea30d9e3a290f5ff95bef77/docs/publib_origin.png -------------------------------------------------------------------------------- /docs/publib_origin_latex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erwanp/publib/57d784850315f03aaea30d9e3a290f5ff95bef77/docs/publib_origin_latex.png -------------------------------------------------------------------------------- /docs/publib_poster_origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erwanp/publib/57d784850315f03aaea30d9e3a290f5ff95bef77/docs/publib_poster_origin.png -------------------------------------------------------------------------------- /publib/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | publib 4 | """ 5 | 6 | from __future__ import absolute_import, division, print_function, unicode_literals 7 | 8 | from .main import set_style, fix_style 9 | from .tools.colors import colors, keep_color, get_next_color 10 | from .tools.tools import reset_defaults, regenerate_fonts 11 | 12 | def __get_version__(): 13 | from os.path import join, dirname 14 | # Read version number from file 15 | with open(join(dirname(__file__), '__version__.txt')) as version_file: 16 | __version__ = version_file.read().strip() 17 | return __version__ 18 | 19 | __version__ = __get_version__() -------------------------------------------------------------------------------- /publib/__version__.txt: -------------------------------------------------------------------------------- 1 | 0.4.0 -------------------------------------------------------------------------------- /publib/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @author: Erwan Pannier 4 | 5 | Produce publication-level quality images on top of Matplotlib 6 | 7 | For similar librairies, see seaborn, which also add neat high-end API to 8 | Matplotlib function calls. 9 | 10 | 11 | Description 12 | -------- 13 | 14 | Use:: 15 | 16 | set_style() # at the beginning of the script 17 | ... 18 | fix_style() # after each new axe is plotted 19 | 20 | Note that importing publib will already load the basic style by default. 21 | 22 | A couple more styles ('poster', 'article', 'origin') can be selected with the 23 | function :func:`~publib.publib.set_style` 24 | 25 | Because some matplotlib parameters cannot be changed before the lines are 26 | plotted, they are called through the function fix_style() which: 27 | - changes the minor ticks 28 | - remove the spines 29 | - turn the legend draggable by default 30 | 31 | Examples 32 | -------- 33 | 34 | import numpy as np 35 | import matplotlib.pyplot as plt 36 | import publib 37 | a = np.linspace(0,6.28) 38 | plt.plot(a,np.cos(a)) # plotted by publib 'basic' style 39 | plt.show() 40 | 41 | publib.set_style('article') 42 | plt.plot(a,a**2) 43 | publib.fix_style('article') 44 | plt.show() 45 | 46 | 47 | Notes 48 | ----- 49 | 50 | Known issues: 51 | 52 | If fonts (ex: Times New Roman) appear to be bold, you may need Matplotlib to regenerate 53 | its font library cache (delete ~/.matplotlib/fontCache) 54 | 55 | See dedicated Stackoverflow:: 56 | 57 | https://stackoverflow.com/questions/33955900/matplotlib-times-new-roman-appears-bold 58 | 59 | """ 60 | 61 | from __future__ import absolute_import, division, print_function, unicode_literals 62 | 63 | import matplotlib.pyplot as plt 64 | import matplotlib as mpl 65 | import os 66 | from os.path import dirname, join 67 | from six import string_types 68 | 69 | style_params = { 70 | 'basic': {'clean_spines': True, 71 | 'draggable_legend': False, 72 | 'draggable_text': False, 73 | 'tight_layout': True, 74 | 'labelpad': 10, 75 | }, 76 | 'article': {'clean_spines': False, 77 | }, 78 | 'article_s': {'clean_spines': False, 79 | 'labelpad': 5, 80 | 'spine_linewidth': 0.5, 81 | }, 82 | 'poster': {}, 83 | 'B&W': {}, 84 | 'talk': {'clean_spines': False}, 85 | 'origin': {'clean_spines': False, 86 | }, 87 | 'latex': {}, 88 | } 89 | 90 | def set_style(style='basic', **kwargs): 91 | ''' Changes Matplotlib basic style to produce high quality graphs. Call 92 | this function at the beginning of your script. You can even further improve 93 | graphs with a call to :py:func:`~publib.main.fix_style` at the end of your script. 94 | 95 | Parameters 96 | ---------- 97 | style: string 98 | 'basic', 'article', 'poster', 'B&W', 'talk', 'origin', 'latex'`` 99 | 100 | kwargs: dict of rcParams 101 | add Matplotlib rcParams 102 | 103 | Examples 104 | -------- 105 | >>> set_style('article') 106 | 107 | >>> set_style('poster',**{'lines.linewidth':2}) 108 | 109 | See Also 110 | -------- 111 | 112 | :func:`~publib.publib.fix_style`, 113 | :func:`~publib.tools.tools.reset_defaults`, 114 | :func:`~publib.tools.tools.regenerate_fonts` 115 | 116 | ''' 117 | 118 | style = _read_style(style) 119 | 120 | # Add basic style as the first style 121 | if style[0] != 'basic': 122 | style = ['basic'] + style 123 | 124 | # Apply all styles 125 | for s in style: 126 | _set_style(s, **kwargs) 127 | 128 | 129 | def _set_style(style, **kwargs): 130 | 131 | stl = _get_style(style) 132 | 133 | if not os.path.exists(stl): 134 | # avail = os.listdir() 135 | avail = [f.replace('.mplstyle', '') for f in os.listdir( 136 | _get_lib()) if f.endswith('.mplstyle')] 137 | raise ValueError('{0} is not a valid style. '.format(stl) + 138 | 'Please pick a style from the list available in ' + 139 | '{0}: {1}'.format(_get_lib(), avail)) 140 | 141 | mpl.style.use(stl) 142 | 143 | for k in kwargs: 144 | mpl.rcParams[k] = kwargs[k] 145 | 146 | return 147 | 148 | 149 | def fix_style(style='basic', ax=None, **kwargs): 150 | ''' 151 | Add an extra formatting layer to an axe, that couldn't be changed directly 152 | in ``matplotlib.rcParams`` or with styles. Apply this function to every axe 153 | you created. 154 | 155 | Parameters 156 | ---------- 157 | ax: a matplotlib axe. 158 | If None, the last axe generated is used 159 | style: string or list of string 160 | ``['basic', 'article', 'poster', 'B&W', 'talk', 'origin', 'latex']`` 161 | one of the styles previously defined. It should match the style you 162 | chose in set_style but nothing forces you to. 163 | kwargs: dict 164 | edit any of the style_params keys. ex:: 165 | 166 | >>> tight_layout=False 167 | 168 | Examples 169 | -------- 170 | 171 | :: 172 | 173 | from publib import set_style, fix_style 174 | set_style('poster') 175 | plt.plot(a,np.cos(a)) 176 | fix_style('poster',**{'draggable_legend':False}) 177 | 178 | See Also 179 | -------- 180 | 181 | :func:`~publib.publib.set_style`, 182 | :func:`~publib.tools.tools.reset_defaults` 183 | 184 | ''' 185 | 186 | style = _read_style(style) 187 | 188 | # Apply all styles 189 | for s in style: 190 | if not s in style_params.keys(): 191 | raise ValueError('{0} is not a valid style. '.format(s)+ 192 | 'Please pick a style from the following: {0}. '.format(style_params.keys())+\ 193 | 'Or update `style_params` in publib.main.py') 194 | 195 | _fix_style(style, ax, **kwargs) 196 | 197 | 198 | def _fix_style(styles, ax=None, **kwargs): 199 | 200 | # Start with basic params 201 | params = style_params['basic'] 202 | 203 | # Apply all styles params 204 | for s in styles: 205 | for p, v in style_params[s].items(): 206 | params[p] = v 207 | 208 | # User defined params: 209 | for k in kwargs: 210 | params[k] = kwargs[k] 211 | 212 | if ax is None: 213 | try: 214 | ax = plt.gca() 215 | except: 216 | raise ValueError('Please select an axis') 217 | 218 | if 'spine_linewidth' in params.keys(): 219 | for spine in ['left', 'bottom', 'right', 'top']: 220 | ax.spines[spine].set_linewidth(params['spine_linewidth']) 221 | 222 | if params['clean_spines']: 223 | ax.yaxis.set_ticks_position('left') 224 | ax.xaxis.set_ticks_position('bottom') 225 | ax.spines['right'].set_visible(False) 226 | ax.spines['top'].set_visible(False) 227 | 228 | # Tight layout 229 | if params['tight_layout']: 230 | plt.tight_layout() 231 | 232 | # Labelpads, offsets, etc. 233 | ax.xaxis.labelpad = params['labelpad'] 234 | ax.yaxis.labelpad = params['labelpad'] 235 | 236 | titleoffset = 1.05 237 | ax.title.set_y(titleoffset) 238 | 239 | # Minorticks: 240 | if not ax.get_xscale() == 'log': 241 | minor_locatorx = mpl.ticker.AutoMinorLocator(2) 242 | ax.xaxis.set_minor_locator(minor_locatorx) 243 | if not ax.get_yscale() == 'log': 244 | minor_locatory = mpl.ticker.AutoMinorLocator(2) 245 | ax.yaxis.set_minor_locator(minor_locatory) 246 | 247 | # Render legend draggable: 248 | if params['draggable_legend']: 249 | l = ax.get_legend() 250 | if not l is None: 251 | try: 252 | l.set_draggable(True) 253 | except AttributeError: # Deprecated method 254 | l.draggable(True) 255 | 256 | if params['draggable_text']: 257 | for t in ax.get_children(): 258 | if type(t) == mpl.text.Annotation: 259 | t.draggable(True) 260 | 261 | return 262 | 263 | 264 | def _read_style(style): 265 | ''' Deal with different style format (str, list, tuple) 266 | 267 | Returns 268 | ------- 269 | 270 | style: list 271 | list of styles 272 | ''' 273 | 274 | if isinstance(style, string_types): 275 | style = [style] 276 | else: 277 | style = list(style) 278 | 279 | return style 280 | 281 | 282 | def _get_style(style): 283 | ''' Get absolute path of style file ''' 284 | return join(_get_lib(),'{0}.mplstyle'.format(style)) 285 | 286 | def _get_lib(): 287 | ''' Get absolute path of styles ''' 288 | return join(dirname(os.path.realpath(__file__)),'stylelib') 289 | 290 | # %% On start-up 291 | 292 | set_style('basic') # whenever publib is imported 293 | 294 | 295 | 296 | if __name__ == '__main__': 297 | from test.test_functions import run_testcases 298 | run_testcases() 299 | -------------------------------------------------------------------------------- /publib/stylelib/B&W.mplstyle: -------------------------------------------------------------------------------- 1 | # Author: Erwan Pannier 2 | # A Matplotlib style to provide publication-level quality images 3 | 4 | axes.prop_cycle: cycler('color',['k']) -------------------------------------------------------------------------------- /publib/stylelib/article.mplstyle: -------------------------------------------------------------------------------- 1 | # Author: Erwan Pannier 2 | # A Matplotlib style to provide publication-level quality images 3 | # Note: article should be built on top of default. When importing plotlib default is 4 | # imported already. 5 | 6 | 7 | #figure.dpi: 72 8 | #figure.figsize: 4, 3 9 | 10 | legend.frameon: false 11 | 12 | axes.grid: true 13 | 14 | lines.markersize: 7.0 15 | 16 | #axes.labelsize: 10 17 | #axes.titlesize: 12 18 | #font.size: 10 19 | #legend.fontsize: 10 20 | #xtick.labelsize: 8 21 | #ytick.labelsize: 8 22 | 23 | errorbar.capsize: 5 24 | 25 | font.family: serif 26 | font.sans-serif : Helvetica, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Avant Garde, sans-serif 27 | font.serif: Times, Times New Roman, Bitstream Vera Serif, DejaVu Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Palatino, Charter, serif 28 | -------------------------------------------------------------------------------- /publib/stylelib/article_s.mplstyle: -------------------------------------------------------------------------------- 1 | # Author: Erwan Pannier 2 | # A Matplotlib style to provide publication-level quality images 3 | # Note: article should be built on top of default. When importing plotlib default is 4 | # imported already. 5 | 6 | 7 | figure.dpi: 160 8 | figure.figsize: 4,3 9 | 10 | 11 | axes.grid: true 12 | 13 | legend.borderpad: 0.2 14 | legend.frameon: false 15 | legend.labelspacing: 0.05 16 | legend.numpoints: 1 17 | 18 | grid.linewidth: 0.25 19 | lines.linewidth: 1.0 20 | lines.markeredgewidth: 0.5 21 | lines.markersize: 4.0 22 | 23 | xtick.direction: out 24 | xtick.major.pad: 2.0 25 | xtick.major.size: 3.0 26 | xtick.major.width: 0.5 27 | xtick.minor.pad: 1.5 28 | xtick.minor.size: 1.5 29 | xtick.minor.width: 0.5 30 | ytick.direction: out 31 | ytick.major.pad: 2.0 32 | ytick.major.size: 3.0 33 | ytick.major.width: 0.5 34 | ytick.minor.pad: 1.5 35 | ytick.minor.size: 1.5 36 | ytick.minor.width: 0.5 37 | #errorbar.capsize : 5 38 | 39 | axes.labelsize: 10 40 | axes.titlesize: 12 41 | font.size: 10 42 | legend.fontsize: 10 43 | xtick.labelsize: 8 44 | ytick.labelsize: 8 45 | 46 | font.family: serif 47 | font.sans-serif : Helvetica, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Avant Garde, sans-serif 48 | font.serif: Times, Times New Roman, Bitstream Vera Serif, DejaVu Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Palatino, Charter, serif 49 | -------------------------------------------------------------------------------- /publib/stylelib/basic.mplstyle: -------------------------------------------------------------------------------- 1 | # Author: Erwan Pannier 2 | # A Matplotlib style to provide publication-level quality images 3 | 4 | axes.prop_cycle: cycler('color',['5DA5DA', 'FAA43A', '60BD68', 'F17CB0', 'B2912F', 'B276B2', 'DECF3F', 'F15854', '4D4D4D']) 5 | axes.formatter.use_mathtext: true 6 | axes.grid: false 7 | figure.dpi: 80.0 8 | figure.facecolor: white 9 | figure.figsize: 8, 6 10 | 11 | grid.alpha: 0.2 12 | grid.color: 0.7 13 | grid.linestyle: -- 14 | grid.linewidth: 0.5 15 | 16 | legend.borderpad: 0.4 17 | legend.frameon: true 18 | legend.labelspacing: 0.1 19 | legend.numpoints: 1 20 | 21 | lines.dash_joinstyle: round 22 | lines.linewidth: 2.0 23 | lines.markeredgewidth: 1.0 24 | lines.solid_capstyle: round 25 | lines.solid_joinstyle: round 26 | 27 | patch.edgecolor: 0.5 28 | patch.facecolor: 0.75 29 | 30 | savefig.bbox: tight 31 | savefig.dpi: 300.0 32 | savefig.format: pdf 33 | 34 | text.usetex: false 35 | 36 | xtick.direction: out 37 | xtick.major.pad: 4.0 38 | xtick.major.size: 6.0 39 | xtick.major.width: 1.0 40 | xtick.minor.pad: 3.0 41 | xtick.minor.size: 3.0 42 | xtick.minor.width: 1.0 43 | ytick.direction: out 44 | ytick.major.pad: 4.0 45 | ytick.major.size: 6.0 46 | ytick.major.width: 1.0 47 | ytick.minor.pad: 3.0 48 | ytick.minor.size: 3.0 49 | ytick.minor.width: 1.0 50 | 51 | figure.subplot.top: 0.85 52 | figure.subplot.bottom: 0.15 53 | figure.subplot.left: 0.17 54 | figure.subplot.right: 0.88 55 | 56 | axes.labelsize: 20 57 | axes.titlesize: 24 58 | font.size: 20 59 | legend.fontsize: 20 60 | xtick.labelsize: 16 61 | ytick.labelsize: 16 62 | 63 | font.family : sans-serif 64 | font.style : normal 65 | font.variant : normal 66 | font.weight : normal 67 | font.stretch : normal 68 | font.serif : Bitstream Vera Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif 69 | font.sans-serif : Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif 70 | font.cursive : Apple Chancery, Textile, Zapf Chancery, Sand, Script MT, Felipa, cursive 71 | font.fantasy : Comic Sans MS, Chicago, Charcoal, Impact, Western, Humor Sans, fantasy 72 | font.monospace : Bitstream Vera Sans Mono, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace 73 | -------------------------------------------------------------------------------- /publib/stylelib/latex.mplstyle: -------------------------------------------------------------------------------- 1 | # Author: Erwan Pannier 2 | # A Matplotlib style to provide publication-level quality images 3 | # Note: article should be built on top of default. When importing plotlib default is 4 | # imported already. 5 | 6 | font.family: Latin Modern Math 7 | mathtext.default: regular -------------------------------------------------------------------------------- /publib/stylelib/origin.mplstyle: -------------------------------------------------------------------------------- 1 | # Author: Erwan Pannier 2 | # A Matplotlib style to provide publication-level quality images 3 | # Note: article should be built on top of default. When importing plotlib default is 4 | # imported already. 5 | 6 | axes.prop_cycle: cycler('color',['k', 'r', 'b', 'g', 'orange']) 7 | 8 | 9 | #figure.dpi: 72 10 | #figure.figsize: 4, 3 11 | 12 | legend.frameon: false 13 | 14 | axes.grid: true 15 | 16 | lines.markersize: 7.0 17 | lines.linewidth: 1.0 18 | 19 | #axes.labelsize: 10 20 | #axes.titlesize: 12 21 | #font.size: 10 22 | #legend.fontsize: 10 23 | #xtick.labelsize: 8 24 | #ytick.labelsize: 8 25 | 26 | errorbar.capsize: 5 27 | 28 | font.family: serif 29 | font.sans-serif : Helvetica, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Avant Garde, sans-serif 30 | font.serif: Times, Times New Roman, Bitstream Vera Serif, DejaVu Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Palatino, Charter, serif 31 | -------------------------------------------------------------------------------- /publib/stylelib/poster.mplstyle: -------------------------------------------------------------------------------- 1 | # Author: Erwan Pannier 2 | # A Matplotlib style to provide publication-level quality images 3 | # Note: article should be built on top of default. When importing plotlib default is 4 | # imported already. 5 | 6 | legend.frameon: false 7 | 8 | axes.labelsize: 24 9 | axes.titlesize: 28 10 | font.size: 20 11 | legend.fontsize: 20 12 | xtick.labelsize: 24 13 | ytick.labelsize: 24 14 | 15 | figure.subplot.top: 0.82 16 | figure.subplot.bottom: 0.17 17 | figure.subplot.left: 0.20 18 | figure.subplot.right: 0.90 -------------------------------------------------------------------------------- /publib/stylelib/small.mplstyle: -------------------------------------------------------------------------------- 1 | # Author: Erwan Pannier 2 | # A Matplotlib style to provide publication-level quality images 3 | # 'small': used for Jupyter Notebook for instance 4 | 5 | savefig.dpi: 72 6 | -------------------------------------------------------------------------------- /publib/stylelib/talk.mplstyle: -------------------------------------------------------------------------------- 1 | # Author: Erwan Pannier 2 | # A Matplotlib style to provide publication-level quality images 3 | # Note: this style should be imported on top of `default` style. 4 | # Normally when importing plotlib default is imported automatically. 5 | 6 | legend.frameon: false 7 | 8 | axes.labelsize: 24 9 | axes.titlesize: 28 10 | font.size: 24 11 | legend.fontsize: 24 12 | xtick.labelsize: 20 13 | ytick.labelsize: 20 14 | 15 | lines.markersize: 10 16 | 17 | figure.subplot.top: 0.82 18 | figure.subplot.bottom: 0.17 19 | figure.subplot.left: 0.20 20 | figure.subplot.right: 0.90 21 | 22 | font.family: Arial #serif 23 | font.sans-serif : Helvetica, Arial, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Avant Garde, sans-serif 24 | font.serif: Times New Roman, Times, Bitstream Vera Serif, DejaVu Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Palatino, Charter, serif 25 | -------------------------------------------------------------------------------- /publib/test/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | publib 4 | """ 5 | 6 | from .test_functions import test_routines 7 | -------------------------------------------------------------------------------- /publib/test/test_functions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Apr 8 18:26:37 2018 4 | 5 | @author: erwan 6 | 7 | ------------------------------------------------------------------------------- 8 | 9 | 10 | """ 11 | 12 | from __future__ import absolute_import, print_function 13 | 14 | from publib import set_style, fix_style 15 | from publib.tools.tools import reset_defaults, regenerate_fonts 16 | from publib.tools.fix import fix_bold_TimesNewRoman 17 | import matplotlib as mpl 18 | 19 | # %% Test routines 20 | 21 | def test_routines(**kwargs): 22 | ''' Test that functions dont crash 23 | 24 | No Assert test is currently implemented 25 | 26 | Notes 27 | ----- 28 | 29 | for some reason using latex will also apply to the plot showing 30 | the default behaviour of matplotlib (it seems that this parameter 31 | is retroactive 32 | ''' 33 | 34 | import numpy as np 35 | import matplotlib.pyplot as plt 36 | 37 | # %% Examples 38 | def example1(title, seed): 39 | np.random.seed(seed) 40 | x = np.linspace(0, 5, 250) 41 | y = np.cos(x)**2 + np.random.normal(scale=0.5, size=len(x)) 42 | yav = np.cos(x)**2 43 | plt.figure() 44 | ax = plt.subplot() 45 | ax.plot(x, y, 'o', label='normal distribution') 46 | ax.plot(x, yav, zorder=-1, label='average') 47 | plt.xlabel(r'$x$') 48 | plt.ylabel(r'$\cos^2 x$+noise') 49 | plt.title(title) 50 | plt.legend(loc='upper left') 51 | plt.ylim((-1.5, 3.5)) 52 | plt.show() 53 | return ax 54 | 55 | # def example2(title, seed): 56 | # np.random.seed(seed) 57 | # x = np.linspace(0, 5, 50) 58 | # y = np.cos(x)**2 + 1 * np.random.random(len(x)) 59 | # yerr = np.std(y, axis=0) 60 | # plt.figure() 61 | # ax = plt.subplot() 62 | # ax.errorbar(x, y, yerr=yerr, fmt='o', 63 | # label='new legends are draggable by default') 64 | # plt.xlabel(r'$x$') 65 | # plt.ylabel(r'$\cos^2 x$+noise') 66 | # plt.title(title) 67 | # plt.legend(loc='upper left') 68 | # plt.ylim((-1.5, 3.5)) 69 | # plt.show() 70 | # return ax 71 | # 72 | # def example3(title, seed): 73 | # np.random.seed(seed) 74 | # x = np.linspace(0, 5, 10) 75 | # y = np.cos(x)**2 + 0.1 * np.random.random(len(x)) 76 | # yerr = np.std(y, axis=0) 77 | # plt.figure() 78 | # ax = plt.subplot() 79 | # ax.errorbar(x, y, yerr=yerr, marker='o', capsize=5, # example of use of capsize 80 | # label='scaled legend marker size') 81 | # plt.xlabel(r'$x$') 82 | # plt.ylabel(r'$\cos^2 x$+noise background') 83 | # plt.title(title) 84 | # plt.legend(markerscale=1.3) 85 | # plt.ylim((-1.5, 3.5)) 86 | # plt.show() 87 | # return ax 88 | 89 | # %% Plot them 90 | plt.close('all') 91 | import time 92 | 93 | for example in [example1]: 94 | 95 | seed = int(time.time()) 96 | mpl.rcdefaults() 97 | plt.ion() # force interactive mode (so we're not stuck when run from terminal) 98 | 99 | set_style() 100 | example('basic', seed) 101 | fix_style() 102 | 103 | plt.pause(0.01) 104 | 105 | set_style('article') 106 | example('article', seed) 107 | fix_style('article') 108 | 109 | plt.pause(0.01) 110 | 111 | # set_style(['article','B&W']) 112 | # example('article',seed) 113 | # fix_style(['article','B&W']) 114 | 115 | set_style('poster', **{'lines.linewidth': 5}) 116 | example('poster', seed) 117 | fix_style('poster', **{'draggable_legend': False}) 118 | 119 | plt.pause(0.01) 120 | 121 | set_style(['origin']) 122 | example('OriginPro', seed) 123 | fix_style(['origin']) 124 | 125 | plt.pause(0.01) 126 | 127 | set_style(['origin', 'latex']) 128 | example('OriginPro + latex', seed) 129 | fix_style(['origin', 'latex']) 130 | 131 | plt.pause(0.01) 132 | 133 | # Default plot 134 | mpl.style.use('classic') 135 | example('matplotlib', seed) 136 | 137 | plt.pause(0.01) 138 | 139 | mpl.style.use('ggplot') 140 | example('ggplot', seed) 141 | 142 | plt.pause(0.01) 143 | 144 | return True 145 | 146 | 147 | 148 | def test_tools(): 149 | ''' Test publib tools are called properly ''' 150 | 151 | regenerate_fonts 152 | reset_defaults() 153 | 154 | fix_bold_TimesNewRoman() 155 | 156 | def run_testcases(): 157 | 158 | test_routines() 159 | test_tools() 160 | 161 | if __name__ == '__main__': 162 | run_testcases() -------------------------------------------------------------------------------- /publib/test/test_tools.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 4 | """ 5 | 6 | from publib import set_style 7 | from publib.tools import colors, keep_color, get_next_color 8 | 9 | import matplotlib.pyplot as plt 10 | 11 | 12 | def test_keep_color(*args, **kwargs): 13 | ''' Make sure keep_color reset the color cycle so that 14 | the next color is the same as the previous ''' 15 | 16 | plt.ion() # force interactive mode (so we're not stuck when run from terminal) 17 | 18 | plt.figure() 19 | plt.plot(0,1,'o') 20 | 21 | current_color = get_next_color(nonintrusive=True) 22 | keep_color() 23 | 24 | plt.plot(1,1,'o') 25 | 26 | assert get_next_color(nonintrusive=True) == current_color 27 | 28 | 29 | 30 | if __name__ == '__main__': 31 | 32 | test_keep_color() 33 | 34 | 35 | -------------------------------------------------------------------------------- /publib/tools/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | publib 4 | """ 5 | 6 | from .tools import reset_defaults, regenerate_fonts, list_font_names, list_font_files 7 | from .fix import fix_bold_TimesNewRoman 8 | from .colors import colors, keep_color, get_next_color -------------------------------------------------------------------------------- /publib/tools/colors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 4 | """ 5 | 6 | 7 | from __future__ import absolute_import, division, print_function, unicode_literals 8 | 9 | import matplotlib.pyplot as plt 10 | 11 | # Colors available for import 12 | colors = ['#5DA5DA', 13 | '#FAA43A', 14 | '#60BD68', 15 | '#F17CB0', 16 | '#B2912F', 17 | '#B276B2', 18 | '#DECF3F', 19 | '#F15854', 20 | '#4D4D4D'] 21 | 22 | 23 | 24 | def keep_color(ax=None): 25 | ''' Keep the same color for the same graph. 26 | Warning: due to the structure of Python iterators I couldn't help but 27 | iterate over all the cycle twice. One first time to get the number of elements 28 | in the cycle, one second time to stop just before the last. And this still 29 | only works assuming your cycle doesn't contain the object twice 30 | 31 | Note: when setting color= it looks like the color cycle state is not called 32 | 33 | TODO: maybe implement my own cycle structure 34 | 35 | .. warning:: 36 | only works if all colors in a cycle are unique 37 | ''' 38 | 39 | if ax is None: 40 | ax = plt.gca() 41 | 42 | i = 1 # count number of elements 43 | next_color = ax._get_lines.get_next_color() 44 | a = ax._get_lines.get_next_color() # a is already the next next color. 45 | # do a full cycle : 46 | while(a != next_color): 47 | i += 1 48 | a = ax._get_lines.get_next_color() 49 | print("guessed that cycle has size ", i) 50 | # We want a-1 to show up on next call to next. So a-2 must be set now 51 | for j in range(i - 2): 52 | ax._get_lines.get_next_color() 53 | 54 | print("Expected color is ", next_color) 55 | 56 | return None 57 | 58 | 59 | def get_next_color(ax=None, nonintrusive=True): 60 | ''' Return the next color to be used in the given color cycle. 61 | 62 | Warning: due to the structure of Python iterators I couldn't help but 63 | iterate over all the color cycle once. 64 | 65 | If nonintrusive is True, then leave the color cycle in the same state as 66 | before 67 | 68 | .. warning:: 69 | only works if all colors in a cycle are unique 70 | ''' 71 | 72 | if ax is None: 73 | ax = plt.gca() 74 | 75 | i = 1 # count number of elements 76 | next_color = ax._get_lines.get_next_color() 77 | a = ax._get_lines.get_next_color() # a is already the next next color. 78 | # do a full cycle : 79 | while(a != next_color): 80 | i += 1 81 | a = ax._get_lines.get_next_color() 82 | 83 | if nonintrusive: 84 | # We want a-1 to show up on next call to next. So a-2 must be set now 85 | for j in range(i - 1): 86 | ax._get_lines.get_next_color() 87 | 88 | return next_color 89 | -------------------------------------------------------------------------------- /publib/tools/fix.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Apr 24 14:04:31 2018 4 | 5 | @author: erwan 6 | """ 7 | 8 | from __future__ import absolute_import, division, print_function, unicode_literals 9 | 10 | import matplotlib as mpl 11 | from publib.tools.tools import regenerate_fonts 12 | 13 | def fix_bold_TimesNewRoman(): 14 | ''' For some reason when using Times New Roman it appears bold 15 | This fixes it 16 | 17 | References 18 | ---------- 19 | 20 | https://stackoverflow.com/questions/33955900/matplotlib-times-new-roman-appears-bold 21 | 22 | ''' 23 | 24 | try: 25 | del mpl.font_manager.weight_dict['roman'] 26 | except KeyError: 27 | pass 28 | finally: 29 | regenerate_fonts() 30 | 31 | -------------------------------------------------------------------------------- /publib/tools/tools.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Some tools and tips to fix common Matplotlib bugs 4 | """ 5 | 6 | from __future__ import absolute_import, division, print_function, unicode_literals 7 | 8 | import matplotlib as mpl 9 | from warnings import warn 10 | 11 | def reset(): 12 | 13 | warn(DeprecationWarning('reset replaced by reset_defaults')) 14 | 15 | return reset_defaults() 16 | 17 | def reset_defaults(): 18 | ''' Reset to Matplotlib defaults 19 | 20 | See Also 21 | -------- 22 | 23 | :func:`~publib.publib.set_style` 24 | :func:`~publib.publib.fix_style` 25 | 26 | ''' 27 | 28 | mpl.rcdefaults() 29 | 30 | 31 | 32 | def regenerate_fonts(): 33 | ''' Regenerate Matplotlib font cache 34 | 35 | References 36 | ---------- 37 | 38 | https://bastibe.de/2016-05-30-matplotlib-font-cache.html 39 | 40 | ''' 41 | 42 | mpl.font_manager._rebuild() 43 | 44 | def list_font_names(): 45 | ''' List ttf font names ''' 46 | 47 | return sorted([f.name for f in mpl.font_manager.fontManager.ttflist]) 48 | 49 | def list_font_files(): 50 | ''' List ttf font names ''' 51 | 52 | return {f.name:f.fname for f in sorted(mpl.font_manager.fontManager.ttflist, 53 | key=lambda x: x.name)} -------------------------------------------------------------------------------- /register.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | '''Automatically generate a README.rst for Pypi from my README.md, and publish 3 | the latest version 4 | 5 | Use 6 | ------------ 7 | python register.py 8 | 9 | Requirement 10 | ------------ 11 | pandoc 12 | 13 | ''' 14 | 15 | from __future__ import print_function 16 | 17 | import os 18 | import shutil 19 | 20 | package_name = 'publib' 21 | 22 | # All the rest below is standard: 23 | 24 | if os.path.exists('README.rst'): 25 | os.remove('README.rst') 26 | 27 | os.system('pandoc -s README.md --from markdown --to rst -s -o README.rst') 28 | 29 | 30 | if os.path.exists('README.rst'): 31 | print('Readme generated') 32 | os.system('python setup.py sdist') 33 | os.system('python setup.py bdist_wheel --universal') 34 | os.system("twine upload dist/*") 35 | # Clean 36 | shutil.rmtree('dist') 37 | os.remove('README.rst') 38 | 39 | print('All done') 40 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup, find_packages 3 | import codecs 4 | from os.path import join, dirname 5 | from setuptips import yield_sphinx_only_markup 6 | 7 | long_description = 'Produce publication-level quality images on top of Matplotlib, '+\ 8 | 'with a simple call to a couple functions at the start and end of your script.' 9 | if os.path.exists('README.rst'): 10 | readme_lines = codecs.open('README.rst', encoding="utf-8").readlines() 11 | long_description = ''.join(yield_sphinx_only_markup(readme_lines)) 12 | 13 | # Read version number from file 14 | with open(join(dirname(__file__),'publib', '__version__.txt')) as version_file: 15 | __version__ = version_file.read().strip() 16 | 17 | setup(name='publib', 18 | version=__version__, 19 | description='Produce publication-level quality images on top of Matplotlib', 20 | long_description=long_description, 21 | url='https://github.com/erwanp/publib', 22 | author='Erwan Pannier', 23 | author_email='erwan.pannier@gmail.com', 24 | license='MIT License', 25 | packages=find_packages(), 26 | keywords=["origin", "styles", "matplotlib"], 27 | install_requires=[ 28 | 'matplotlib>=3.8.0', 29 | #'numpy', # for testing only. Should make this an optional requirement. 30 | 'six', 31 | ], 32 | classifiers=[ 33 | 'Development Status :: 4 - Beta', 34 | 'Intended Audience :: Science/Research', 35 | 'License :: OSI Approved :: CEA CNRS Inria Logiciel Libre License, version 2.1 (CeCILL-2.1)', 36 | 'Topic :: Scientific/Engineering', 37 | 'Topic :: Text Processing', 38 | 'Programming Language :: Python', 39 | 'Programming Language :: Python :: 2.7', 40 | 'Programming Language :: Python :: 3.4', 41 | 'Programming Language :: Python :: 3.5', 42 | "Operating System :: OS Independent"], 43 | include_package_data=True, 44 | zip_safe=False) 45 | -------------------------------------------------------------------------------- /setuptips.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Utils for setup.py 4 | """ 5 | 6 | import re 7 | 8 | # Utils to format RST 9 | def yield_sphinx_only_markup(lines): 10 | """ 11 | Cleans-up Sphinx-only constructs (ie from README.rst), 12 | so that *PyPi* can format it properly. 13 | 14 | To check for remaining errors, install ``sphinx`` and run:: 15 | 16 | python setup.py --long-description | sed -file 'this_file.sed' | rst2html.py --halt=warning 17 | 18 | :param file_inp: a `filename` or ``sys.stdin``? 19 | :param file_out: a `filename` or ``sys.stdout`?` 20 | 21 | References 22 | ---------- 23 | 24 | https://stackoverflow.com/questions/16367770/my-rst-readme-is-not-formatted-on-pypi-python-org 25 | 26 | Notes 27 | ----- 28 | 29 | Check output with:: 30 | 31 | python setup.py --long-description | rst2html.py > output.html 32 | 33 | """ 34 | substs = [ 35 | ## Selected Sphinx-only Roles. 36 | # 37 | (r':abbr:`([^`]+)`', r'\1'), 38 | (r':ref:`([^`]+)`', r'`\1`_'), 39 | (r':term:`([^`]+)`', r'**\1**'), 40 | (r':dfn:`([^`]+)`', r'**\1**'), 41 | (r':(samp|guilabel|menuselection):`([^`]+)`', r'``\2``'), 42 | 43 | 44 | ## Sphinx-only roles: 45 | # :foo:`bar` --> foo(``bar``) 46 | # :a:foo:`bar` XXX afoo(``bar``) 47 | # 48 | #(r'(:(\w+))?:(\w+):`([^`]*)`', r'\2\3(``\4``)'), 49 | (r':(\w+):`([^`]*)`', r'\1(``\2``)'), 50 | 51 | 52 | ## Sphinx-only Directives. 53 | # 54 | (r'\.\. doctest', r'code-block'), 55 | (r'\.\. plot::', r'.. '), 56 | (r'\.\. seealso', r'info'), 57 | (r'\.\. glossary', r'rubric'), 58 | (r'\.\. figure::', r'.. '), 59 | 60 | 61 | ## Other 62 | # 63 | (r'\|version\|', r'x.x.x'), 64 | 65 | ## added to make RADIS docs Pypi compatible 66 | (r'\.\. image::', r'.. '), 67 | (r'α', r''), 68 | ] 69 | 70 | regex_subs = [ (re.compile(regex, re.IGNORECASE), sub) for (regex, sub) in substs ] 71 | 72 | def clean_line(line): 73 | try: 74 | for (regex, sub) in regex_subs: 75 | line = regex.sub(sub, line) 76 | except Exception as ex: 77 | print("ERROR: %s, (line(%s)"%(regex, sub)) 78 | raise ex 79 | 80 | return line 81 | 82 | for line in lines: 83 | yield clean_line(line) 84 | --------------------------------------------------------------------------------