I need to paste a pandas DataFrame into the HTML body of a newly generated email draft through a function. The problem is, I need to apply more than one conditional styling to it before it ends in the email draft.
import datetime as dt
import pandas as pd
import win32com.client as win32
def create_mail(text, subject, recipient):
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = recipient
mail.Subject = subject
mail.HtmlBody = text
mail.save()
df = pd.DataFrame(data = {'Number': [100.00, -100.00], 'Date': [dt.date(2020, 1, 1), dt.date(2022, 1, 1)]})
df['Date'] = pd.to_datetime(df['Date']).dt.date
The styles are defined as follows:
def style_negative(v, props = 'color:red;'):
return props if v < 0 else None
def style_red_date(v, props = 'color:red;'):
return props if v < dt.datetime.now().date() else None
Negative numbers in Number column must be colored red.
Dates falling before today in Date column must be colored red as well.
If I apply only one (either) style to the DataFrame object through df.style.applymap(), it works perfectly fine. However, when I want to apply another style to the (now) Styler object through .apply()
df = df.style.applymap(style_negative, subset = ['Number'])
df = df.apply(style_red_date, subset = ['Date'])
I get the following error:
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
The rest of my code:
html = (
df
.format({'Number':"{:.2f}"})
.set_properties(**{'font-size':'11pt'})
.hide_index()
.render()
)
mail_content = """
<html><head></head><body>
{0}
</body></html>
""".format(html)
create_mail(mail_content, "Subject", "")
I've read through this question as to export a style from Styler object, but it seems that it can only be used on a DataFrame object. Is there a way to have multiple formatting rules applied to a DataFrame / Styler object and have it exported as HTML? Am I missing something trivial here?