Reputation: 59544
I use pd.set_option("display.colheader_justify","right")
to set the column header. But I can't find the option for data by pd.describe_option()
.
How to set the data within a dataframe display left or right alignment for each column? Or, is it possible to define a format template for the whole row data display?
Upvotes: 73
Views: 157716
Reputation: 1739
To complement @Hagbard answer, I prefer to apply several styles by using Styler.pipe
def make_pretty(styler):
styler.set_caption("caption")
styler.format(subset=["number"], precision=2)
styler.bar(subset=["number"], cmap="PuBu")
styler.set_properties(**{'text-align': 'left'})
styler.set_table_styles([dict(selector='th', props=[('text-align', 'left')])])
return styler
df.head().style.pipe(make_pretty)
Upvotes: 0
Reputation: 6223
Since solutions using pandas.Styler
don't work in console printing (at least for me), I came up with the following code using pandas 1.3.3 and an example dataframe, printing all string columns left aligned (w/o header):
df = pd.DataFrame({'float': [0.123, 7],
'int': [3, 357676],
'str': ["hello world", "bye"],
'cat': pd.Series(["a", "bbb"], dtype="category"),
'bool': [True, False]
})
formatters = {}
for col in df.select_dtypes("object"):
len_max = df[col].str.len().max()
formatters[col] = lambda _: f"{_:<{len_max}s}"
print(df.to_string(formatters=formatters))
float int str cat bool
0 0.123 3 hello world a True
1 7.000 357676 bye bbb False
If you also want to align the header left, add justify='left'
. For some reason the header is now one character too far to left for some columns, but not for all:
print(df.to_string(formatters=formatters, justify="left"))
float int str cat bool
0 0.123 3 hello world a True
1 7.000 357676 bye bbb False
However applying this pattern to other dtypes fails (also for string columns). I have no idea why this occurs. Be aware that string conversion is added below via astype
, also inside the f-string via the !s
flag (see f-string documentation):
formatters = {}
for col in df.columns:
len_max = df[col].astype(str).str.len().max()
formatters[col] = lambda _: f"{_!s:<{len_max}s}"
print(col, len_max)
print(df.to_string(formatters=formatters))
float int str cat bool
0 0.123 3 hello world a True
1 7.0 357676 bye bbb False
Upvotes: 10
Reputation: 73
Also looking to be able to print left-aligned tables to the console/terminal, I accomplished this with a somewhat modified approach from those given:
def whatever_scope():
...
# Closure for the formatter. do whatever fancy formatting you want here.
def leftalign(len):
def format(v):
return(f"{v:<{len}}")
return(format)
# create formatters for all columns
formatters = {}
for col in df.columns:
maxlen = df[col].astype(str).str.len().max()
formatters[col] = leftalign(maxlen)
# use the formatters
# remember that `justify` is just for column headers
text_tbl = df.to_string(
justify="left",
formatters=formatters,
index=False,
)
...
Upvotes: 0
Reputation: 178
The solutions using style
didn't work for me for left-aligning the text in the headers or cells, for displaying the table in jupyter. And I didn't want to install new libraries just for this
Instead you can get an html representation of the table, change that to specify that all should be left aligned, and display.
Here is a function to do exactly that:
import IPython.display
def display_left_aligned_df(df):
html_table = df.to_html(notebook=True)
html_table = html_table.replace('<td>', '<td style="text-align:left">').replace('<th>', '<th style="text-align:left">')
IPython.display.display(IPython.display.HTML(html_table))
The notebook=True
option means the html generated is intended for display in a notebook. So for example length of text in each cell is truncated.
This worked perfectly to generate a jupyter-style table for the dataframe, but left aligned.
Upvotes: 0
Reputation: 979
Instead of justifying all columns the same way, I had a need to justify some columns differently. Since there was no mention in this thread, I thought of reminding the presence of the subset
option:
Styler.set_properties(subset=None, **kwargs)[source]
From the same example as the OP, one could left justify just the 'text' column:
df = pd.DataFrame({'text': ['foo', 'bar'],
'number': [1, 2]})
dfStyler = df.style.set_properties(subset=['text'],**{'text-align': 'left'})
Upvotes: 6
Reputation: 747
pip3 install tabulate
from tabulate import tabulate
df = pd.DataFrame ({'Text': ['abcdef', 'x'], 'Value': [12.34, 4.2]})
print(tabulate(df, showindex=False, headers=df.columns))
Text Value
------ -------
abcdef 12.34
x 4.2
This will automatically align pandas header and column data to good view format. Automatically align pandas dataframes columns data to left. Removes showing of the index in pandas dataframe. Puts ---- between the header and column data.
Upvotes: 15
Reputation: 410
I wrapped @Hagbard's answer in a function to use it whenever I wish to display a pandas dataframe consisting English text on a notebook cell:
from pandas import DataFrame
def left_align(df: DataFrame):
left_aligned_df = df.style.set_properties(**{'text-align': 'left'})
left_aligned_df = left_aligned_df.set_table_styles(
[dict(selector='th', props=[('text-align', 'left')])]
)
return left_aligned_df
To show a dataframe, I simply write this:
left_align(df.head())
Caution: For large datasets, it prints all the rows and columns of df
without any abstraction, so Jupyter crashes! That's why I use it with .head()
or .tail()
or some other limit.)
Upvotes: 4
Reputation: 5940
If you wanna align both text and header to the left for example you can use:
df.style.set_properties(**{'text-align': 'left'}).set_table_styles([ dict(selector='th', props=[('text-align', 'left')] ) ])
This first sets the text to the left and then the header.
Upvotes: 2
Reputation: 3700
The answer given by @Romain is great but I would like to summarize some comments:
# Test data
df = DataFrame({'text': ['foo', 'bar'],'number': [1, 2]})
dfStyler = df.style.set_properties(**{'text-align': 'left'})
dfStyler.set_table_styles([dict(selector='th', props=[('text-align', 'left')])])
will align all table text and the column headers as well.
Upvotes: 24
Reputation: 16147
In my situation, I have a class wrapper around my Pandas DataFrame. This allows me to left-justify the DataFrame's string output by customizing the wrapper's __str__()
method.
Here's how I solved the problem for my application, based on Unutbu's answer to a similar question. The Pandas DataFrame is referenced by self.data
:
def __str__(self):
"""
Return the test stats report as a single string
with left-justified columns.
"""
# Columns containing boolean values need different format strings
# to avoid 'ValueError: Invalid format specifier' exceptions.
BOOL_COLUMNS = ['success',]
formatters = {}
for li in list(self.data.columns):
if li in BOOL_COLUMNS:
form = "{{!s:<5}}".format()
else:
max = self.data[li].str.len().max()
form = "{{:<{}s}}".format(max)
formatters[li] = functools.partial(str.format,form)
return self.data.to_string(formatters=formatters, index=False)
Upvotes: 1
Reputation: 451
you can control it by a new context:
with pd.option_context('display.colheader_justify','right'):
...
Upvotes: 2