Source code for pyjams.text2plot

#!/usr/bin/env python
"""
Write text on a plot

This module was written by Matthias Cuntz while at Department of Computational
Hydrosystems, Helmholtz Centre for Environmental Research - UFZ, Leipzig,
Germany, and continued while at Institut National de Recherche pour
l'Agriculture, l'Alimentation et l'Environnement (INRAE), Nancy, France.

:copyright: Copyright 2014-2022 Matthias Cuntz, see AUTHORS.rst for details.
:license: MIT License, see LICENSE for details.

.. moduleauthor:: Matthias Cuntz

The following functions are provided:

.. autosummary::
   text2plot
   abc2plot
   signature2plot

History
    * Written Nov 2021 by Matthias Cuntz (mc (at) macu (dot) de)
      combining abc2plot and signature2plot
    * Written abc2plot, May 2012, Matthias Cuntz
    * Added parenthesis option to abc2plot, Feb 2013, Arndt Piayda
    * Ported to Python 3, Feb 2013, Matthias Cuntz
    * Added opening and closing parentheses, brackets, braces,
      Feb 2013, Matthias Cuntz
    * Options usetex and mathrm, Feb 2013, Matthias Cuntz
    * Options mathbf, large and making medium the default,
      Feb 2013, Matthias Cuntz
    * Added string option, Nov 2013, Matthias Cuntz
    * Corrected bug in medium as default, Nov 2013, Matthias Cuntz
    * Make usetex work with fontsize keyword of axis.text()
      of matplotllib v1.1.0, Nov 2013, Matthias Cuntz
    * Written signature2plot, Jan 2014, Matthias Cuntz
    * Assert that small or large is set if medium is not None (abc2plot),
      Feb 2014, Matthias Cuntz
    * Replace horizontalalignment='left' and verticalalignment='bottom'
      by kwargs mechanism (abc2plot), May 2014, Matthias Cuntz
    * Added option italic (abc2plot), May 2014, Matthias Cuntz
    * Added options xlarge, xxlarge, xsmall, xxsmall (abc2plot),
      Oct 2015, Matthias Cuntz
    * Make numpy docstring format (abc2plot), Nov 2020, Matthias Cuntz
    * Ported into pyjams, Nov 2021, Matthias Cuntz
    * dx, dy, and name mandatory parameters (signature2plot),
      Nov 2020, Matthias Cuntz
    * Change option name parenthesis -> parentheses, Nov 2021, Matthias Cuntz
    * Written text2plot, Nov 2021, Matthias Cuntz
    * Use text2plot for signature2plot, Nov 2021, Matthias Cuntz
    * Use text2plot for abc2plot, Nov 2021, Matthias Cuntz
    * More consistent docstrings, Jan 2022, Matthias Cuntz
    * Added upper keyword in abc2plot, Jun 2024, Matthias Cuntz

"""
import time as ptime
from .str2tex import str2tex
from .romanliterals import int2roman
# from pyjams.str2tex import str2tex
# from pyjams.romanliterals import int2roman
from warnings import warn, filterwarnings
filterwarnings("default", category=DeprecationWarning)


__all__ = ['text2plot', 'abc2plot', 'signature2plot']


[docs] def text2plot(handle, dx, dy, itext, small=False, medium=False, large=False, xsmall=False, xxsmall=False, xlarge=False, xxlarge=False, bold=False, italic=False, usetex=False, mathrm=False, **kwargs): # pragma: no cover """ Write text on plot Parameters ---------- handle : :class:`matplotlib.axes` subclass Matplotlib axes handle dx : float % of xlim from min(xlim) dy : float % of ylim from min(ylim) itext : str String to write on plot small : bool, optional fontsize='small' if True (default: False) medium : bool, optional fontsize='medium' if True (default: False). Medium is taken if no other fontsize is chosen. large : bool, optional fontsize='large' if True (default: False) xlarge : bool, optional fontsize='x-large' if True (default: False) xsmall : bool, optional fontsize='x-small' if True (default: False) xxlarge : bool, optional fontsize='xx-large' if True (default: False) xxsmall : bool, optional fontsize='xx-small' if True (default: False) bold : bool, optional fontweight='bold' if True, else fontsize='normal' (default) italic : bool, optional fontstyle='italic' if True, else fontstyle='normal' (default) usetex : bool, optional Embed into LaTeX math environment if True, else no LaTeX math mode (default) mathrm : bool, optional If True, put text into appropriate LaTeX mathrm/mathit/mathbf environment if *usetex==True* and *italic==True* or *bold==True*. If False, use standard math font if *usetex==True* (default). string : bool, optional Treat *iplot* as literal string and not as integer if True (default: False). *integer*, *roman* and *lower* are disabled then. **kwargs : dict, optional All additional parameters are passed passed to :meth:`matplotlib.axes.Axes.text()` Returns ------- String on plot Examples -------- .. code-block:: python text2plot(ax, 0.7, 0.6, r'CO$_2$', large=True, usetex=usetex, mathrm=False) """ import matplotlib.pyplot as plt warn('The plotting functions of pyjams were transferred to a' ' standalone repository "mcplot". text2plot is hence deprecated' ' in pyjams.', category=DeprecationWarning) # Check input ifont = small + medium + large + xsmall + xxsmall + xlarge + xxlarge assert ifont <= 1, ('only one of small, medium, large, xsmall, xxsmall' ' xlarge, or xxlarge font size can be chosen.') if ifont == 0: medium = True if usetex and mathrm: assert (bold + italic) <= 1, ('if usetex and mathrm: then bold and' ' italic are mutually exclusive.') # Size if small: fs = 'small' elif medium: fs = 'medium' elif large: fs = 'large' elif xsmall: fs = 'x-small' elif xxsmall: fs = 'xx-small' elif xlarge: fs = 'x-large' elif xxlarge: fs = 'xx-large' else: # just for security fs = 'medium' # Weight if bold: fw = 'bold' else: fw = 'normal' # Style if italic: fst = 'italic' else: fst = 'normal' # usetex istr = str2tex(itext, usetex=usetex) if usetex: if mathrm: if bold: istr = istr.replace('mathrm', 'mathbf') elif italic: istr = istr.replace('mathrm', 'mathit') # x/y position xmin, xmax = handle.get_xlim() ymin, ymax = handle.get_ylim() idx = xmin + dx * (xmax - xmin) if 'transform' in kwargs: if kwargs['transform'] is handle.transAxes: idx = dx idy = ymin + dy * (ymax - ymin) if 'transform' in kwargs: if kwargs['transform'] is handle.transAxes: idy = dy handle.text(idx, idy, istr, fontsize=fs, fontweight=fw, fontstyle=fst, **kwargs)
[docs] def abc2plot(handle, dx, dy, iplot, integer=False, roman=False, lower=False, upper=None, parentheses=None, brackets=None, braces=None, bold=False, italic=False, usetex=False, mathrm=False, string=False, **kwargs): # pragma: no cover """ Write a, B, iii, IV, e), etc. on plots Parameters ---------- handle : :class:`matplotlib.axes` subclass Matplotlib axes handle dx : float % of xlim from min(xlim) dy : float % of ylim from min(ylim) iplot : int or str Number of plot starting with 1, or string if 'string==True' integer : bool, optional Use integers instead of a, b, c if True (default: False) roman : bool, optional Use Roman literals instead of a, b, c if True (default: False) lower : bool, optional Use lowercase letters for a, b, c if True, else use uppercase letters (default). lower=True and upper=True are mutually exclusive. upper : bool, optional Use uppercase letters for A, B, C if True (default), else use lowercase letters. lower=True and upper=True are mutually exclusive. parentheses : str or None, optional Parentheses before or after the letter/number. Possible values are 'open', 'close', 'both', 'None', and *None*. 'open' puts opening parentheses in front of the letter/number. 'close' puts closing parentheses after the letter/number. 'both' puts opening and closing parentheses around the letter/number. 'None' and *None* do not put any parentheses before or after the letter/number (default). brackets : str or None, optional Brackets before or after the letter/number. Possible values are 'open', 'close', 'both', 'None', and *None*. 'open' puts opening brackets in front of the letter/number. 'close' puts closing brackets after the letter/number. 'both' puts opening and closing brackets around the letter/number. 'None' and *None* do not put any brackets before or after the letter/number (default). braces : str or None, optional Braces before or after the letter/number. Possible values are 'open', 'close', 'both', 'None', and *None*. 'open' puts opening braces in front of the letter/number. 'close' puts closing braces after the letter/number. 'both' puts opening and closing braces around the letter/number. 'None' and *None* do not put any braces before or after the letter/number (default). bold : bool, optional fontweight='bold' if True, else fontsize='normal' (default) italic : bool, optional fontstyle='italic' if True, else fontstyle='normal' (default) usetex : bool, optional Embed into LaTeX math environment if True, else no LaTeX math mode (default) mathrm : bool, optional If True, put text into appropriate LaTeX mathrm/mathit/mathbf environment if *usetex==True* and *italic==True* or *bold==True*. If False, use standard math font if *usetex==True* (default). string : bool, optional Treat *iplot* as literal string and not as integer if True (default: False). *integer*, *roman* and *lower* are disabled then. **kwargs : dict, optional All additional parameters are passed passed to :func:`text2plot()` Returns ------- Letter/number or string on plot Notes ----- If output is a letter then iplot > 26 gives unexpected results. Examples -------- .. code-block:: python abc2plot(ax, 0.7, 0.6, 2, large=True, parentheses='both', usetex=usetex, mathrm=False) """ import matplotlib.pyplot as plt # Check input assert not (roman and integer), ( 'either Roman literals or integers can be chosen.') iparentheses = False if parentheses is not None: if parentheses != 'None': iparentheses = True ibrackets = False if brackets is not None: if brackets != 'None': ibrackets = True ibraces = False if braces is not None: if braces != 'None': ibraces = True ibrack = iparentheses + ibrackets + ibraces assert ibrack <= 1, ('only one of parentheses, brackets, or braces' ' can be chosen.') if upper is not None: assert not (upper and lower), ( 'either uppercase or lowercase can be chosen.') # assure correct lower keyword if upper=False given if upper: lower = False else: lower = True # Number or letter if string: t = str(iplot) else: if roman: t = int2roman(iplot, lower=lower) elif integer: t = str(iplot) else: if lower: t = chr(96 + iplot) else: t = chr(64 + iplot) # parentheses if iparentheses: if parentheses.lower() == 'open': t = '(' + t elif parentheses.lower() == 'close': t = t + ')' elif parentheses.lower() == 'both': t = '(' + t + ')' elif parentheses.lower() == 'none': pass else: raise ValueError("parentheses must be either 'open', 'close'," " 'both', or 'none'.") if ibrackets: if brackets.lower() == 'open': t = '[' + t elif brackets.lower() == 'close': t = t + ']' elif brackets.lower() == 'both': t = '[' + t + ']' elif brackets.lower() == 'none': pass else: raise ValueError("brackets must be either 'open', 'close'," " 'both', or 'none'.") if ibraces: if braces.lower() == 'open': if usetex or (plt.get_backend() == 'pdf'): t = r'\{' + t else: t = '{' + t elif braces.lower() == 'close': if usetex or (plt.get_backend() == 'pdf'): t = t + r'\}' else: t = t + '}' elif braces.lower() == 'both': if usetex or (plt.get_backend() == 'pdf'): t = r'\{' + t + r'\}' else: t = '{' + t + '}' elif braces.lower() == 'none': pass else: raise ValueError("braces must be either 'open', 'close'," " 'both', or 'none'.") if usetex: if mathrm: if bold: t = r'\mathbf{' + t + '}' elif italic: t = r'\mathit{' + t + '}' else: t = r'\mathrm{' + t + '}' t = r'$' + t + r'$' text2plot(handle, dx, dy, t, bold=bold, italic=italic, usetex=False, mathrm=False, **kwargs)
[docs] def signature2plot(handle, dx, dy, itext, **kwargs): # pragma: no cover """ Write a copyright notice on a plot The notice is: '(C) YYYY *itext*', where YYYY is the current 4-digit year. Parameters ---------- handle : :class:`matplotlib.axes` subclass Matplotlib axes handle dx : float % of xlim from min(xlim) dy : float % of ylim from min(ylim) itext : str Text after '(C) YYYY', where YYYY is the current 4-digit year **kwargs : dict, optional All additional parameters are passed passed to :func:`text2plot()` Returns ------- '(C) YYYY itext' or '(C) YYYY' on plot, where YYYY is the 4-digit year Notes ----- Signature will be right-aligned horizontally if horizontalalignment or ha are not given in kwargs. Examples -------- .. code-block:: python signature2plot(ax, 0., 0.05, 'M Cuntz, INRAE', small=True, italic=True, usetex=usetex, mathrm=True) """ year = str(ptime.localtime().tm_year) if itext.strip(): otext = r'$\copyright$ ' + year + ' ' + itext.strip() else: otext = r'$\copyright$ ' + year if ('horizontalalignment' not in kwargs) and ('ha' not in kwargs): kwargs['horizontalalignment'] = 'right' text2plot(handle, dx, dy, otext, **kwargs)
if __name__ == '__main__': import doctest doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE) # outtype = '' # # outtype = 'pdf' # pdffile = 'text2plot.pdf' # usetex = True # textsize = 12 # import matplotlib as mpl # if (outtype == 'pdf'): # mpl.use('PDF') # set directly after import matplotlib # import matplotlib.pyplot as plt # from matplotlib.backends.backend_pdf import PdfPages # # Customize: http://matplotlib.sourceforge.net/users/customizing.html # mpl.rc('ps', papersize='a4', usedistiller='xpdf') # ps2pdf # mpl.rc('figure', figsize=(8.27, 11.69)) # a4 portrait # if usetex: # mpl.rc('text', usetex=True) # else: # import matplotlib.pyplot as plt # mpl.rc('figure', figsize=(4./5.*8.27, 4./5.*11.69)) # a4 portrait # mpl.rc('path', simplify=False) # do not remove # if (outtype == 'pdf'): # print('Plot PDF ', pdffile) # pdf_pages = PdfPages(pdffile) # else: # print('Plot X') # figsize = mpl.rcParams['figure.figsize'] # # -------------------------------------------------------------- # # text2plot # fig = plt.figure() # sub = fig.add_axes([0.05, 0.05, 0.4, 0.4]) # m = plt.plot(range(100), 'k:') # text2plot(sub, 0.0, 0.0, r'CO$_2$') # text2plot(sub, 0.1, 0.1, 'CO2', usetex=usetex) # text2plot(sub, 0.2, 0.2, r'$\frac{CO_2}{O_2}$', xxsmall=True, # usetex=usetex, mathrm=False) # text2plot(sub, 0.3, 0.3, r'Units (m$^2$ s$^{-1}$)', xsmall=True, # usetex=usetex, mathrm=False) # text2plot(sub, 0.4, 0.4, r'Two \n lines', medium=True, # usetex=False, mathrm=False) # text2plot(sub, 0.5, 0.5, r'Units \newline (m$^2$ s$^{-1}$)', large=True, # usetex=usetex, mathrm=False) # text2plot(sub, 0.6, 0.6, r'CO$_2$', xlarge=True, # usetex=usetex, mathrm=False) # text2plot(sub, 0.7, 0.7, r'CO$_2$', xxlarge=True, # usetex=usetex, mathrm=False) # text2plot(sub, 0.8, 0.8, r'CO$_2$', medium=True, bold=True, # usetex=usetex, mathrm=True) # # -------------------------------------------------------------- # # abc2plot # fig = plt.figure() # sub = fig.add_axes([0.05, 0.05, 0.4, 0.4]) # m = plt.plot(range(100), 'k:') # abc2plot(sub, 0, 0, 2) # abc2plot(sub, 0.1, 0.1, 2, parentheses='close') # abc2plot(sub, 0.2, 0.2, 2, lower=True, parentheses='open') # abc2plot(sub, 0.3, 0.3, 2, roman=True, parentheses='both') # abc2plot(sub, 0.4, 0.4, 2, roman=True, lower=True, parentheses='none') # abc2plot(sub, 0.5, 0.5, 2, integer=True, parentheses='both', # usetex=usetex) # abc2plot(sub, 0.5, 0.6, 2, small=True, medium=False, # large=False, parentheses='both', usetex=usetex, # mathrm=False) # abc2plot(sub, 0.6, 0.6, 2, small=False, medium=True, # large=False, parentheses='both', usetex=usetex, # mathrm=False) # abc2plot(sub, 0.7, 0.6, 2, small=False, medium=False, # large=True, parentheses='both', usetex=usetex, # mathrm=False) # abc2plot(sub, 0.7, 0.7, 2, medium=True, brackets='both', # usetex=usetex, mathrm=True) # abc2plot(sub, 0.8, 0.8, 2, medium=True, bold=True, # braces='both', usetex=usetex, mathrm=True) # sub = fig.add_axes([0.5, 0.5, 0.4, 0.4]) # m = plt.plot(range(100), 'k:') # abc2plot(sub, 0.1, 0.1, 2, brackets='close') # abc2plot(sub, 0.2, 0.2, 2, lower=True, brackets='open') # abc2plot(sub, 0.3, 0.3, 2, roman=True, brackets='both', # usetex=usetex, mathrm=False) # abc2plot(sub, 0.4, 0.4, 2, roman=True, lower=True, # brackets='none') # abc2plot(sub, 0.5, 0.5, 2, integer=True, braces='close') # abc2plot(sub, 0.6, 0.6, 2, small=True, braces='open', # usetex=usetex, mathrm=True) # abc2plot(sub, 0.7, 0.7, 2, medium=True, braces='both', # horizontalalignment='left', verticalalignment='bottom') # abc2plot(sub, 0.8, 0.8, 2, medium=True, bold=True, braces='none', # horizontalalignment='right', verticalalignment='top') # # -------------------------------------------------------------- # # signature2plot # import numpy as np # fig = plt.figure() # sub = fig.add_axes([0.05, 0.05, 0.4, 0.4]) # mulx = 1. # muly = 1. # m = plt.plot(mulx*np.arange(100)/99., muly*np.arange(100)/99., 'k:') # signature2plot(sub, mulx*0.5, muly*0.5, 'Test1', usetex=usetex) # signature2plot(sub, mulx*0.6, muly*0.6, 'MC1', small=True, # usetex=usetex) # - # signature2plot(sub, mulx*0.7, muly*0.7, 'Test2', large=True, # usetex=usetex, italic=True) # signature2plot(sub, mulx*0.8, muly*0.8, 'MC2', bold=True, usetex=usetex, # ha='left', mathrm=True) # signature2plot(sub, mulx*0.8, muly*0.8, 'MC2', bold=True) # signature2plot(sub, mulx*0.9, muly*0.9, 'Test3', large=True, # usetex=usetex, italic=True, mathrm=True) # signature2plot(sub, mulx*1.0, muly*1.0, 'MC3', usetex=usetex, bold=True, # horizontalalignment='left') # signature2plot(sub, 0.9, 0.1, 'MM', transform=sub.transAxes, # usetex=usetex, bold=True, horizontalalignment='center') # if (outtype == 'pdf'): # pdf_pages.savefig(fig) # plt.close() # if (outtype == 'pdf'): # pdf_pages.close() # else: # plt.show()