"Fossies" - the Fresh Open Source Software Archive

Member "veusz-3.1/veusz/utils/formatting.py" (19 Feb 2018, 7914 Bytes) of package /linux/privat/veusz-3.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "formatting.py" see the Fossies "Dox" file reference documentation.

    1 #    Copyright (C) 2010 Jeremy S. Sanders
    2 #    Email: Jeremy Sanders <jeremy@jeremysanders.net>
    3 #
    4 #    This program is free software; you can redistribute it and/or modify
    5 #    it under the terms of the GNU General Public License as published by
    6 #    the Free Software Foundation; either version 2 of the License, or
    7 #    (at your option) any later version.
    8 #
    9 #    This program is distributed in the hope that it will be useful,
   10 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12 #    GNU General Public License for more details.
   13 #
   14 #    You should have received a copy of the GNU General Public License along
   15 #    with this program; if not, write to the Free Software Foundation, Inc.,
   16 #    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   17 ###############################################################################
   18 
   19 from __future__ import division
   20 import re
   21 import math
   22 import numpy as N
   23 
   24 from . import dates
   25 
   26 _formaterror = 'FormatError'
   27 
   28 # a format statement in a string
   29 _format_re = re.compile(r'%([-#0-9 +.hlL]*?)([diouxXeEfFgGcrs%])')
   30 
   31 def localeFormat(totfmt, args, locale=None):
   32     """Format using fmt statement fmt, qt QLocale object locale and
   33     arguments to formatting args.
   34 
   35     * arguments are not supported in this formatting, nor is using
   36     a dict to supply values for statement
   37     """
   38 
   39     # substitute all format statements with string format statements
   40     newfmt = _format_re.sub("%s", totfmt)
   41 
   42     # do formatting separately for all statements
   43     strings = []
   44     i = 0
   45     for f in _format_re.finditer(totfmt):
   46         code = f.group(2)
   47         if code == '%':
   48             s = '%'
   49         else:
   50             try:
   51                 s = f.group() % args[i]
   52                 i += 1
   53             except IndexError:
   54                 raise TypeError("Not enough arguments for format string")
   55             s = s.replace('-', u'\u2212')
   56             if locale is not None and code in 'eEfFgG':
   57                 s = s.replace('.', locale.decimalPoint())
   58 
   59         strings.append(s)
   60 
   61     if i != len(args):
   62         raise TypeError("Not all arguments converted during string formatting")
   63 
   64     return newfmt % tuple(strings)
   65 
   66 def sciToHuman(val, cleanup=False):
   67     """Convert output from C formatting to human scientific notation.
   68     if cleanup, remove zeros after decimal points
   69     """
   70 
   71     # split around the exponent
   72     leader, exponent = val.split('e')
   73 
   74     # strip off trailing decimal point and zeros if no format args
   75     if cleanup and leader.find('.') >= 0:
   76         leader = leader.rstrip('0').rstrip('.')
   77 
   78     # trim off leading 1
   79     if leader == '1' and cleanup:
   80         leader = ''
   81     else:
   82         # add multiply sign
   83         leader += u'\u00d7'
   84 
   85     return '%s10^{%i}' % (leader, int(exponent))
   86 
   87 def formatSciNotation(num, formatargs, locale=None):
   88     """Format number into form X \times 10^{Y}.
   89     This function trims trailing zeros and decimal point unless a formatting
   90     argument is supplied
   91 
   92     This is similar to the %e format string
   93     formatargs is the standard argument in a format string to control the
   94     number of decimal places, etc.
   95 
   96     locale is a QLocale object
   97     """
   98 
   99     # handle nan, inf, -inf
  100     if not N.isfinite(num):
  101         return str(num)
  102 
  103     # create an initial formatting string
  104     if formatargs:
  105         formatstr = '%' + formatargs + 'e'
  106     else:
  107         formatstr = '%.10e'
  108 
  109     # do formatting, catching errors
  110     try:
  111         text = formatstr % num
  112     except:
  113         return _formaterror
  114 
  115     text = sciToHuman(text, cleanup=formatargs=='')
  116 
  117     # do substitution of decimals
  118     if locale is not None:
  119         text = text.replace('.', locale.decimalPoint())
  120 
  121     return text
  122 
  123 def formatGeneral(num, fmtarg, locale=None):
  124     """General formatting which switches from normal to scientic
  125     notation."""
  126 
  127     if fmtarg:
  128         # if an argument is given, we convert output
  129         try:
  130             retn = ('%'+fmtarg+'g') % num
  131         except ValueError:
  132             retn = _formaterror
  133         if retn.find('e') >= 0:
  134             # in scientific notation, so convert
  135             retn = sciToHuman(retn, cleanup=False)
  136     else:
  137         a = abs(num)
  138         # manually choose when to switch from normal to scientific
  139         # as the default %g isn't very good
  140         if a >= 1e4 or (a < 1e-2 and a > 1e-110):
  141             retn = formatSciNotation(num, fmtarg, locale=locale)
  142         else:
  143             retn = '%.10g' % num
  144 
  145     if locale is not None:
  146         # replace decimal point with correct decimal point
  147         retn = retn.replace('.', locale.decimalPoint())
  148     return retn
  149 
  150 engsuffixes = ( 'y', 'z', 'a', 'f', 'p', 'n',
  151                 u'\u03bc', 'm', '', 'k', 'M', 'G',
  152                 'T', 'P', 'E', 'Z', 'Y' )
  153 
  154 def formatEngineering(num, fmtarg, locale=None):
  155     """Engineering suffix format notation using SI suffixes."""
  156 
  157     if num != 0.:
  158         logindex = math.log10( abs(num) ) / 3.
  159 
  160         # for numbers < 1 round down suffix
  161         if logindex < 0. and (int(logindex)-logindex) > 1e-6:
  162             logindex -= 1
  163 
  164         # make sure we don't go out of bounds
  165         logindex = min( max(logindex, -8),
  166                         len(engsuffixes) - 9 )
  167 
  168         suffix = engsuffixes[ int(logindex) + 8 ]
  169         val = num / 10**( int(logindex) *3)
  170     else:
  171         suffix = ''
  172         val = num
  173 
  174     text = ('%' + fmtarg + 'g%s') % (val, suffix)
  175     if locale is not None:
  176         text = text.replace('.', locale.decimalPoint())
  177     return text
  178 
  179 # catch general veusz formatting expression
  180 _formatRE = re.compile(r'%([-0-9.+# ]*)(VDVS|VD.|V.|[A-Za-z%])')
  181 
  182 def formatNumber(num, formatstr, locale=None):
  183     """ Format a number in different ways.
  184 
  185     formatstr is a standard C format string, with some additions:
  186      %Ve    scientific notation X \times 10^{Y}
  187      %Vg    switches from normal notation to scientific outside 10^-2 to 10^4
  188      %VE    engineering suffix option
  189 
  190      %VDx   date formatting, where x is one of the arguments in
  191             http://docs.python.org/lib/module-time.html in the function
  192             strftime
  193     """
  194 
  195     outitems = []
  196     while formatstr:
  197         # repeatedly try to do string format
  198         match = _formatRE.search(formatstr)
  199         if not match:
  200             outitems.append(formatstr)
  201             break
  202 
  203         # argument and type of formatting
  204         farg, ftype = match.groups()
  205 
  206         # special veusz formatting
  207         if ftype[:1] == 'V':
  208             # special veusz formatting
  209             if ftype == 'Ve':
  210                 out = formatSciNotation(num, farg, locale=locale)
  211             elif ftype == 'Vg':
  212                 out = formatGeneral(num, farg, locale=locale)
  213             elif ftype == 'VE':
  214                 out = formatEngineering(num, farg, locale=locale)
  215             elif ftype[:2] == 'VD':
  216                 d = dates.floatToDateTime(num)
  217                 # date formatting (seconds since start of epoch)
  218                 if ftype[:4] == 'VDVS':
  219                     # special seconds operator
  220                     out = ('%'+ftype[4:]+'g') % (d.second+d.microsecond*1e-6)
  221                 else:
  222                     # use date formatting
  223                     try:
  224                         out = d.strftime(str('%'+ftype[2:]))
  225                     except ValueError:
  226                         out = _formaterror
  227             else:
  228                 out = _formaterror
  229 
  230             # replace hyphen with true minus sign
  231             out = out.replace('-', u'\u2212')
  232         elif ftype == '%':
  233             out = '%'
  234         else:
  235             # standard C formatting
  236             try:
  237                 out = localeFormat('%' + farg + ftype, (num,), locale=locale)
  238             except:
  239                 out = _formaterror
  240 
  241         outitems.append(formatstr[:match.start()])
  242         outitems.append(out)
  243         formatstr = formatstr[match.end():]
  244 
  245     return ''.join(outitems)