Search code examples
pythonmatplotlibnumbersstring-formattingfixed-point

Combine fixed and locale notation for string formatting


I am trying to define a format string using Python's string format mini-language in order to get a string with a number in fixed notation, but with a local decimal separator. See the following snippet for further clarification of the desired output:

import locale
import os

if os.name == 'nt':
    locale.setlocale(locale.LC_ALL, 'de-de')    
else:
    locale.setlocale(locale.LC_ALL, 'de_de')

number = 1.234567
print('fixed notation:   {:.7f}'.format(number))
print('general notation: {:.7g}'.format(number))
print('local format:     {:.7n}'.format(number))

desired_output = '{:.7f}'.format(number)
print('desired output:   {}'.format(desired_output.replace('.', ',')))

Replacing . with , is a suitable workaround when using 'regular' strings. However, this seems not to be doable in my case since I need to specify a matplotlib.ticker.StrMethodFormatter to get the desired output as tick labels. Using the locale notation works as expected:

ax.yaxis.set_major_formatter(ticker.StrMethodFormatter('{x:1.3n}'))

Unfortunately, I was not able to find a format string for a combined format of fixed (e.g. {:.3f}) and locale notation ({:.3n}) to enable trailing zeros filled for same decimal length.

As you can see in my sample diagram, they should have both equal amount of decimal places (which can be ensured by fixed point notation '{:.7f}') and local decimal separator (which can be ensured by '{:.7n}'):

enter image description here


Solution

  • If you have a function which returns a string in the desired format, you may use this function to format your ticklabels via a FuncFormatter. In this case,

    func = lambda x,pos: '{:.7f}'.format(x).replace('.', ',')
    ax.yaxis.set_major_formatter(mticker.FuncFormatter(func))
    

    This will of course be independent of the locale.

    I don't know if it's possible to use the locale with the formatting mini language but the same approach from above can be extended to use the actual locale

    func2 = lambda x,pos: locale.format('%.7f', x, grouping = True)
    

    In both cases the result should be similar and something like

    enter image description here