bigbug
bigbug

Reputation: 59544

How to set the pandas dataframe data left/right alignment?

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

Answers (12)

auraham
auraham

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

ascripter
ascripter

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

Kevin
Kevin

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

gnoodle
gnoodle

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

Heelara
Heelara

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

Shah Vipul
Shah Vipul

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

Shahrokh Bah
Shahrokh Bah

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())

enter image description here

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

Federico Gentile
Federico Gentile

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

Hagbard
Hagbard

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

JS.
JS.

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

mozlingyu
mozlingyu

Reputation: 451

you can control it by a new context:

with pd.option_context('display.colheader_justify','right'):
    ...

Upvotes: 2

Romain
Romain

Reputation: 21948

If you want to change the display in a Jupyter Notebook, you can use the Style feature.

# Test data
df = DataFrame({'text': ['foo', 'bar'],
                 'number': [1, 2]})

df.style.set_properties(**{'text-align': 'right'})

enter image description here

Upvotes: 40

Related Questions