问题
I read a lot of discussion about this on SE, but still can't find the right one.
I want to plot some numbers, of various lengths, with the same number of digits.
For example I have: 12.345678
, 1.2345678
. Now, since I have to plot them with their error, I want that each one has a different format, in order that they are significant.
So, I want to plot them with a variable number of decimals. In my case, it makes no sense to plot 23.45678+/-1.23456
but better is 23.4+/-1.2
. On the other hand, I need that 1.234567+/-0.034567
becomes 1.23+/-0.03
.
So, let's say, I want to plot all the numbers with a fixed width, could be 3 digits in total plus the comma. I should use something like '%1.1f' %num
, but I can't find the right way. How can I do that?
回答1:
I recommend defining a class that interprets a string formatter to give what you want.
Inside that class, you determine the length of the integer portion of your float and use that to define the appropriate string format.
In a nutshell, the class creates a formatter like '{:4.1f}'
if your input is 12.345
(because you have two digits before the decimal separator) and {:4.2f}
if your input it 1.2345
(because you have only one digit before the decimal separator). The total number of digits (4
in this example) is provided as an input.
The new formatter is: {:nQ}
where n
is the total number of digits (so in the above example, you'd specify {:4Q}
to get the output you want.
Here's the code:
import math
class IntegerBasedFloat(float):
def __format__(self, spec):
value = float(self)
# apply the following only, if the specifier ends in Q
# otherwise, you maintain the original float format
if spec.endswith('Q'):
# split the provided float into the decimal
# and integer portion (for this math is required):
DEC, INT = math.modf(value)
# determine the length of the integer portion:
LEN = len(str(abs(int(INT))))
# calculate the number of available decimals
# based on the overall length
# the -1 is required because the separator
# requires one digit
DECIMALS = int(spec[-2]) - LEN - 1
if DECIMALS < 0:
print 'Number too large for specified format'
else:
# create the corresponding float formatter
# that can be evaluated as usual:
spec = spec[-2] + '.' + str(DECIMALS) + 'f'
return format(value, spec)
DATA = [12.345, 2.3456, 345.6789]
print '{:4Q}'.format(IntegerBasedFloat(DATA[0]))
print '{:4Q}'.format(IntegerBasedFloat(DATA[1]))
print '{:4Q}'.format(IntegerBasedFloat(DATA[2]))
print 'This is a "custom" float: {:5Q} and a "regular" float: {:5.3f}'.format(IntegerBasedFloat(12.3456),12.3456)
The output should be:
12.3
2.35
346
This is a "custom" float: 12.35 and a "regular" float: 12.346
This answer is inspired by:
- splitting a number into the integer and decimal parts in python
- Add custom conversion types for string formatting
来源:https://stackoverflow.com/questions/25197194/fixed-digits-number-in-floats