1

I have to present the difference between two percentages using Python. For example, the difference between 40% and 41.234% is 1.234 percentage points, or 1.234 pp.

If I wanted to format the increase as a percentage, I would use the format specifier {:.0%}:

increase = 0.01234

"{:+.3%} ".format(increase)
>>> "+1.234 %"

What I'm looking for

A format specifier that replaces the % with pp, like this:

"{some_specifier} ".format(increase)
>>> "+1.234 pp"

What I'm not looking for

I know that I could use f-strings like this

f"{increase * 100:+.3f} pp"
>>> "+1.234 pp"

but I'm specifically looking for a format specifier that I can use with .format().

Edit

I realised that a little bit of background may be useful here. In my implementation, the increase can represent a normal float, integer, percentage or percentage point. In order to get the right representation, I have use a variable-format mapping that looks something like:

format_mapping = {
    "var_x": "{:,.0f}",    # for large numbers
    "var_y": "{:+.3f}",    # for small numbers
    "var_z": "{:.4%}",     # for percentages
}

The variable names represent the column names of a pandas dataframe my_data, so that I can then apply the formatting to those columns, for the sake of reporting

for var in my_data.columns:
    fmt = format_mapping[var]
    my_data[var] = pd.Series(fmt.format(value) for value in my_data[var])
KenHBS
  • 6,756
  • 6
  • 37
  • 52
  • 3
    Have you considered just doing `"{:+.3%} ".format(increase).replace('%', 'pp')` instead of trying to make the f-string output 'pp' itself? – Green Cloak Guy Aug 03 '20 at 13:36
  • That's a nice idea. I have a situation, though, where I have different variable types (percentages, floats, integers) that can be used as input for `increase`. I currently use a dictionary mapping between variable-types and format-specifiers to get the format I'm looking for. The format-specifier can then just be used without actually changing the `"{format_specifier}.format(value)"` syntax – KenHBS Aug 03 '20 at 13:41

3 Answers3

2

There are maybe things you can do with inline pipes and subclassing a Format class, but in this case I think it might be easier to just write functions to handle it:

def pct(num, digits=0):
    return '{:+.{}} pp'.format(num * 100, digits)

...

f"{pct(increase, 4)}"
# '+1.234 pp'

you can then put all those functions in their own file, if you want, and invoke them by just calling them in f-strings.

Green Cloak Guy
  • 23,793
  • 4
  • 33
  • 53
1

You could use the following:

increase = 0.01234

print("{:+.4} {}".format(increase*100, "pp"))

Result:

+1.234 pp
David Duran
  • 1,786
  • 1
  • 25
  • 36
1

You can declare custom formatter and replace "%" with "pp" by overriding Formatter.format_field() method:

from string import Formatter    

class MyFormatter(Formatter):
    def format_field(self, value, spec):
        if spec.endswith("p"):
            return super(MyFormatter, self).format_field(value, spec[:-1] + "%")[:-1] + "pp"
        else:
            return super(MyFormatter, self).format_field(value, spec)

Usage:

print(MyFormatter().format("%: {0:+.3%}; pp: {0:+.3p}", 0.01234))

P.S. In python 3 you can use super() without arguments.

Olvin Roght
  • 7,677
  • 2
  • 16
  • 35