georgehere
georgehere

Reputation: 630

Adding a header/description section to a dataframe Pandas Python

I want to place a header value below the title of the data frame data below and get the Expected output, How would I be able to do that?

import pandas as pd

class SubclassedDataFrame(pd.DataFrame):

    # normal properties
    _metadata = ['description']

    @property
    def _constructor(self):
        return SubclassedDataFrame

data = {"a": [1, 2, 3], "b": [10, 12, 13], "c": [230, 1, 3],"d": [8, 12, 9],}

df = SubclassedDataFrame(data)
title = 'Outputs'
header = 'header'

df = df.style.set_caption(title).set_table_styles([{
    'selector': 'caption',
    'props': [
        ('color', 'red'),
        ('font-size', '15px'),
        ('font-style', 'italic'),
        ('font-weight', 'bold'),
        ('text-align', 'center')
    ]
}])

display(df)

Output:

enter image description here

Expected output:

enter image description here

  header

enter image description here

Upvotes: 4

Views: 5208

Answers (1)

Henry Ecker
Henry Ecker

Reputation: 35676

There are 2 approaches:

One approach is to create a MultiIndex with header being the top level:

title = 'Outputs'
header = 'header'

# Add MultiIndex Header
df.columns = pd.MultiIndex.from_product([[header], df.columns])
styler = df.style.set_caption(title).set_table_styles([{
    'selector': 'caption',
    'props': [
        ('color', 'red'),
        ('font-size', '15px'),
        ('font-style', 'italic'),
        ('font-weight', 'bold'),
        ('text-align', 'center')
    ]
}])

display(styler)

Header as MultiIndex

This approach keeps the integrity of the pandas Styler object, and makes "header" a part of the table object, being the first row in thead.


The second approach is to create a Subclass of the Styler object and modify the jinja templates.

templates/myhtml.tpl:

{% extends "html_table.tpl" %}
{% block table %}
<div class="wrap">
    {% if table_title %}
    <h1 class="table-title">{{ table_title}}</h1>
    {% endif %}
    {% if table_header %}
    <h2 class="table-header">{{ table_header }}</h2>
    {% endif %}
{{ super() }}
</div>
{% endblock table %}

templates/mystyles.tpl:

{% extends "html_style.tpl" %}
{% block style %}
{{ super() }}
<style>
    .wrap {
        display: inline-block;
    }

    .table-title {
        color: red;
        font-size: 15px !important;
        font-style: italic;
        font-weight: bold;
        text-align: center;
        margin: 0 2px !important;
    }

    .table-header {
        text-align: center;
        font-size: 13px !important;
        margin: 0 2px !important;
    }
</style>
{% endblock style %}
title = 'Outputs'
header = 'header'

# Build Styler Subclass from templates
MyStyler = Styler.from_custom_template(
    "templates",               # Folder to Search
    html_table="myhtml.tpl",   # HTML Template
    html_style='mystyles.tpl'  # CSS Template
)
# Get Styler For `df`
styler = MyStyler(df)
# Render with arguments and display
HTML(styler.render(table_title=title, table_header=header))

Styled table with h1 and h2 elements

This approach moves some of the control away from the Styler object to the templates, but allows significantly more flexibility as it can be used to create additional HTML elements which is currently not supported by the Styler object.


Environment jupyter-notebook

Setup:

import pandas as pd
from IPython.display import HTML, display
from pandas.io.formats.style import Styler


class SubclassedDataFrame(pd.DataFrame):
    # normal properties
    _metadata = ['description']

    @property
    def _constructor(self):
        return SubclassedDataFrame


data = {
    "a": [1, 2, 3],
    "b": [10, 12, 13],
    "c": [230, 1, 3],
    "d": [8, 12, 9]
}

df = SubclassedDataFrame(data)

Upvotes: 5

Related Questions