fixed field width for float python [duplicate] - python

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?

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 (4in 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

Related

Python : Conversion of float to string keeping all digits of decimal place

I have a task to count the digits after decimal place.
For which I am using the below code :
str(string_name)[::-1].find('.')
But while converting float to string, it is removing the trailing zeroes :
my_string = 16.520440
print(str(my_string ))
output - '16.52044'
expected output - '16.520440'
Since that trailing zero is not a significant digit, there is no way you can do this within the given paradigm. Floats are stored by value, not by the visual representation of the original input. For instance:
my_string_1 = 16.52044
my_string_2 = 16.520440
my_string_3 = 16.5204400
my_string_4 = 016.5204400
All assign exactly the same value to the LHS variable: they have the same binary representation. Leading and trailing zeros do not, by definition, affect this value. There is no way to differentiate the original input from the stored value.
If you want some such effect, then you need to use some other form of original value that incorporates that information. For instance, you could add a second variable that denotes the quantity of significant decimal places -- which is the opposite of what you're trying to achieve -- or perhaps make the original input a string, from which you could derive that information.

how to round up the number for array format in .txt output i n python

I am trying to extract my analysis result in .txt file. The results show as below :
-3.298409999999999854e+04 -3.298409999999999854e+04
-3.297840000000000146e+04 -3.297840000000000146e+04
Code:
anodeIdx = [10,20,30]
stressAnodeXX = [x for i,x in enumerate(stress_xx[0].Y) if i in anodeIdx]
stressAnodeYY = [x for i,x in enumerate(stress_yy[0].Y) if i in anodeIdx]
np.savetxt('Stress_strain_Anode.txt',np.c_[stressAnodeXX,stressAnodeYY])
I expected the result to be -32984.1 but the actual output is -3.2984099999e+4
To save the number in a specific way, you can use optional parameter fmt of np.savetxt(). Documentation
In your case:
np.savetxt('Stress_strain_Anode.txt',np.c_[stressAnodeXX,stressAnodeYY], fmt='%.1f')
f is specifier wihch saves the number as decimal floating point.
.1 Represents how many decimal numbers should be after the decimal point.
I think the problem here is not the numbers not being rounded, but not being appropiately formatted.
You could use the fmt keyword argument of numpy.savetxt to solve this. (numpy documentation):
np.savetxt('Stress_strain_Anode.txt', np.c_[stressAnodeXX,stressAnodeYY], fmt='%.1f')
Where '%.1f' is a format string which formats numbers with one decimal digit.
Your result is actually -32984.1. Float representation in binary code is not ideal so you see it in a bit confusing way. If you want, you can just round your result (but it is not needed):
np.round(your_result_number, decimals=1)
which will return:
-32984.1
More about your result:
-3.2984099999e+4 has two confusing parts:
099999 in the end of number
e+4 in the end of output
e+4 is a scientific notation of your number. It means: "multiply it to 10^4=10000. If you will do it, you will get 3.29841 * 10000 = 32984.1
099999... in the end of the number appears because computer tries to represent decimal float number in binary code, which leads to small "errors". So your result is actually -32984.1.

Python - Convert scientific notation string to float retaining decimal places

I am using python to read some float values from a file. The values read are input to an 'Ada'(Programming Language) program.
The values being read are in different formats (scientific, decimal) and I would like to retain the format.
Everything works well with simple float() operation except when converting '1.0e-5' to float.
>>float('1.0e-5')
#returns 1e-5
1e-5 when used in Ada program gives
error:negative exponent not allowed for integer literal
1.0e-35 works with ada program.
I know if I use format I can get 1.0e-5
>>>"{:.1E}".format(float('1.0e-5'))
#returns '1.0E-5'
But this changes format for other read values also as my reading/manipulation function is common.
How should I approach this problem?
and if
float('1.0')
#returns 1.0
why same behavior is not followed when converting a scientific notation string to float?
(My reading/manipulation function is common. Using formatter string will change the formatting of other read values also)
You could use a custom float to string conversion function which checks if the number will be accepted by Ada using a regular expression (which tests if there are only non-dots before the exponent character, and in which case only convert with format):
import re
def ada_compliant_float_as_string(f):
return "{:.1e}".format(f) if re.match("^-?[^\.]e",str(f)) else str(f)
for f in [-1e-5,1e-5,1.4e-5,-12e4,1,1.0]:
print(ada_compliant_float_as_string(f))
prints:
-1.0e-05
1.0e-05
1.4e-05
-120000.0
1
1.0
only the first value is corrected, other values are just the string representation of a float, unchanged.

How can I convert a float in a str without losing significant figures?

I want to convert the number 0.054000 in a str, but when I write srt(0.054000) I get '0.054'. I need to get '0.054000'. How can I do it?
I have a data file with numbers as my example (0.054000). I need to count the digits of each number. I don't know how to read that number in a way that I count seven digits, for instance.
I think that Dan Patterson's method is the only way to do it reliably - python makes no differentiation between .0054 and .054000: e.g.
>>> .0054 is .0054000
True
Thus you will probably have to simply specify the number of digits you have in sig figs, either using his method or (str(.0054000) + "0"*number_of_sig_figs).
A format specifier starts with a colon and then may contain any of the terms shown
in brackets in the following (each of the terms is optional)
: [[fill]align] [sign] [#] [0] [width] [,] [.precision] [type]
A brief description of the [.precision] is provided below.
.precision: Maximum number of characters for strings (integer); number of digits of
precision for floats. For f, F, e, and E type specifiers this is the number
of digits to the right of the decimal point.
We can use this to specify the precision of our float value:
a=0.540000
print("{:06f}".format(a))
This gives the desired output:
0.540000
Hope this was helpful!

Fixed digits number in floats

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?
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 (4in 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

Categories