10

Hi i am using Pandas and displaying a table. I there a function to apply alternate row color to make it clear to read. Using below code I am sending table in mail and it works.

my code:

count = 1000
df = pandas.DataFrame.from_dict(result)
df["Total"] = df.T.sum()

html = """<!DOCTYPE html>
<html>
    <body>
    <h3> %i</h3>
    {table_content}
    </body>
</html>
""" % count


# Create message container - the correct MIME type is
# multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = " Report"
msg['From'] = sender
msg['To'] = recipients


part2 = MIMEText(html.df(
    table_content=df.to_html(na_rep="0")), 'html')

msg.attach(part2)
Vinod HC
  • 1,557
  • 5
  • 20
  • 38

3 Answers3

8

You can use CSS, namely the tr:nth-child in combination with df.to_html(classes)

Adopt to your case:

from IPython.display import display, HTML
from sklearn.datasets import load_iris
import pandas as pd
import numpy as np

iris = load_iris()
df = pd.DataFrame(data= np.c_[iris['data'], iris['target']],
                     columns= iris['feature_names'] + ['target'])
HTML('''
        <style>
            .df tbody tr:nth-child(even) { background-color: lightblue; }
        </style>
        ''' + df.to_html(classes="df"))

Screenshot from Jupyter notebook

Update: Expanding to a specific example

I slightly rearranged the code to allow adding css, as it was conflicting with {} used by .format. You can add your variables to html_variables dict and use %()s to embed them into html. If your html becomes too complicated I recommend looking at using some template engine to make it more robust. Otherwise the code below should be self-explanatory.

html_template = '''<!DOCTYPE html>
<html>
    <head>
    <style>.df tbody tr:nth-child(even) {background-color: lightblue;}</style>
    </head>
    <body>
    <h3>%(other_var)s</h3>
    %(table_content)s
    </body>
</html>
'''

html_vars = {'other_var':'IRIS Dataset','table_content':df.to_html(classes="df")}

html = html_template % html_vars

# Create message container - the correct MIME type is
# multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Report"
msg['From'] = sender
msg['To'] = recipient

part2 = MIMEText(html, 'html')
msg.attach(part2)
Oleg Medvedyev
  • 1,574
  • 14
  • 16
  • Hi Torrinos, Thank you! if I jut put this html contents in display (HTML(....))) it prints just object and not the actual table. In my case I am assigning html template to variable called html so how can I achieve this in my case. – Vinod HC Mar 09 '17 at 12:23
  • Try the example above. I am having issues replicating your case exactly - don't want to set up the smtp server to try sending a message, I am checking that html renders correctly using Jupyter notebook. The example above works for me. – Oleg Medvedyev Mar 10 '17 at 02:56
6

Old question, but I found a solution within pandas framework which I put for future use:

    def rower(data):
        s = data.index % 2 != 0
        s = pd.concat([pd.Series(s)] * data.shape[1], axis=1) #6 or the n of cols u have
        z = pd.DataFrame(np.where(s, 'background-color:#f2f2f2', ''),
                     index=data.index, columns=data.columns)
        return z

df.style.apply(rower, axis=None)
kontur
  • 4,934
  • 2
  • 36
  • 62
lorenzo
  • 397
  • 4
  • 16
2

Essentially the same as @oleg's answer, but rather than the html blocks you can use df.style.set_table_styles like such:

df.style.set_table_styles([{"selector":"tbody tr:nth-child(even)","props":[("background-color","lightgrey")]}])

I find it useful to use the df.style and have my own dark-theme styler. Feel free to use if it is helpful:

def dfdark(styler):
    #styler.background_gradient(cmap='coolwarm')
    #styler.color('white')
    styler.set_table_styles([
        {
            "selector":"thead",
            "props":[("background-color","grey")]
        },
        {
            "selector":"tbody tr:nth-child(even)",
            "props":[("background-color","lightgrey")]
        },
        {
            "selector":"th.row_heading",
            "props":[("background-color","grey")]
        },
        {
            "selector":"td",
            "props":[("border","white")]
        },

    ])
    return styler
    #styler.format(color='grey')

df=pd.DataFrame(index=np.arange(10),columns=[1,2],data=np.random.normal(size=[10,2]))

df.style.pipe(dfdark)

which outputs:

enter image description here

Vlox
  • 717
  • 8
  • 18