""" """ import copy import operator import re import threading class _Config: @property def lock(self): return self._lock @property def use_unicode(self): with self.lock: return copy.copy(self._use_unicode) @use_unicode.setter def use_unicode(self, val): self._use_unicode = bool(val) def __init__(self): self._lock = threading.RLock() self._use_unicode = False config = _Config() superscripts = ['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'] def superscript(val): items = re.split(r'\*{2}([\d]+)(?!\.)', val) ret = [] while items: try: s = items.pop(0) e = items.pop(0) ret.append(s+''.join(superscripts[int(i)] for i in e)) except IndexError: ret.append(s) return ''.join(ret) def format_units(udict): ''' create a string representation of the units contained in a dimensionality ''' num = [] den = [] keys = [k for k, o in sorted( ((k, k.format_order) for k in udict), key=operator.itemgetter(1) ) ] for key in keys: d = udict[key] if config.use_unicode: u = key.u_symbol else: u = key.symbol if d>0: if d != 1: u = u + ('**%s'%d).rstrip('0').rstrip('.') num.append(u) elif d<0: d = -d if d != 1: u = u + ('**%s'%d).rstrip('0').rstrip('.') den.append(u) res = '*'.join(num) if len(den): if not res: res = '1' fmt = '(%s)' if len(den) > 1 else '%s' res = res + '/' + fmt%('*'.join(den)) if not res: res = 'dimensionless' return res def format_units_unicode(udict): res = format_units(udict) res = superscript(res) res = res.replace('**', '^').replace('*','·') return res def format_units_latex(udict,font='mathrm',mult=r'\\cdot',paren=False): ''' Replace the units string provided with an equivalent latex string. Division (a/b) will be replaced by \frac{a}{b}. Exponentiation (m**2) will be replaced with superscripts (m^{2}) The latex is set with the font argument, and the default is the normal, non-italicized font mathrm. Other useful options include 'mathnormal', 'mathit', 'mathsf', and 'mathtt'. Multiplication (*) are replaced with the symbol specified by the mult argument. By default this is the latex \\cdot symbol. Other useful options may be '' or '*'. If paren=True, encapsulate the string in '\\left(' and '\\right)' The result of format_units_latex is encapsulated in $. This allows the result to be used directly in Latex in normal text mode, or in Matplotlib text via the MathText feature. Restrictions: This routine will not put CompoundUnits into a fractional form. ''' res = format_units(udict) if res.startswith('(') and res.endswith(')'): # Compound Unit compound = True else: # Not a compound unit compound = False # Replace division (num/den) with \frac{num}{den} res = re.sub(r'(?P.+)/(?P.+)',r'\\frac{\g}{\g}',res) # Replace exponentiation (**exp) with ^{exp} res = re.sub(r'\*{2,2}(?P\d+)',r'^{\g}',res) # Remove multiplication signs res = re.sub(r'\*','{'+mult+'}',res) if paren and not compound: res = r'\left(%s\right)' % res res = fr'$\{font}{{{res}}}$' return res def format_units_html(udict,font='%s',mult=r'⋅',paren=False): ''' Replace the units string provided with an equivalent html string. Exponentiation (m**2) will be replaced with superscripts (m2}) No formating is done, change `font` argument to e.g.: '%s' to have text be colored blue. Multiplication (*) are replaced with the symbol specified by the mult argument. By default this is the latex ⋅ symbol. Other useful options may be '' or '*'. If paren=True, encapsulate the string in '(' and ')' ''' res = format_units(udict) if res.startswith('(') and res.endswith(')'): # Compound Unit compound = True else: # Not a compound unit compound = False # Replace exponentiation (**exp) with ^{exp} res = re.sub(r'\*{2,2}(?P\d+)',r'\g',res) # Remove multiplication signs res = re.sub(r'\*',mult,res) if paren and not compound: res = '(%s)' % res res = font % res return res