Preface
Though this problem references the pandas
and numpy
packages I believe a solution does not require working knowledge of either of these packages.
Setup
I wish to create a dictionary of lambda functions to pass to the formatter argument of the pandas function pandas.DataFrame.to_latex.
I would like the dictionary of lambda functions to format floats to a number of digits as specified by a list.
Example
What I would like to achieve may best be seen by example. Let's set up some floats we'd like to format:
import numpy as np
import pandas as pd
y = np.array([[0.12345, 0.12345, 0.12345]])
colnames = ['col1', 'col2', 'col3']
df = pd.DataFrame(y, columns=colnames)
#print(df)
# col1 col2 col3
#0 0.12345 0.12345 0.12345
Excellent, now I'd like to format column col1
to show 1 digit after the decimal point. Similarly, I'd like to format col2
to show 2 digits after the decimal point and col3
to display 3 digits. Let's set up a list with this intention:
digits = [1, 2, 3]
From this list we shall create a dict of lambda functions to format the columns, and test the functions after creation.
fun = {}
for id, col in enumerate(['col1', 'col2', 'col3']):
fun[col] = lambda x : '{{:.{}f}}'.format(digits[id]).format(x)
print(fun[col](0.12345))
# Prints 0.1, 0.12, 0.123 (looks to have worked!)
In the code above printing on creation of each entry appears I have achieved what I wished to. However, looking again I see I was mistaken
print(fun['col1'](0.12345)) # Prints 0.123
print(fun['col2'](0.12345)) # Prints 0.123
print(fun['col3'](0.12345)) # Prints 0.123
I understand that these functions all format the float the same as digits[id] = 3
after the loop.
I would like to alter how I create the lambda functions such that we instead observe:
print(fun['col1'](0.12345)) # Prints 0.1
print(fun['col2'](0.12345)) # Prints 0.12
print(fun['col3'](0.12345)) # Prints 0.123
Is it possible to do this? I imagine a solution may involve use of eval
but I can't figure it out.
Obvious solution
Outside of the context of pd.DataFrame.to_latex
, we could create a single lambda function which takes two arguments and formats floats as desired:
fun = lambda x, digit : '{{:.{}f}}'.format(digit).format(x)
print(fun(0.12345, digits[0])) # Prints 0.1
print(fun(0.12345, digits[1])) # Prints 0.12
print(fun(0.12345, digits[2])) # Prints 0.123
However, as far as I understand the formatter functions passed to pd.DataFrame.to_latex
may only take a single argument and so such a solution would not be viable.