Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Displaying Styled Dataframes Inline #49

Closed
nutcrackerhf opened this issue Aug 24, 2016 · 6 comments
Closed

Displaying Styled Dataframes Inline #49

nutcrackerhf opened this issue Aug 24, 2016 · 6 comments

Comments

@nutcrackerhf
Copy link

Hi - thanks for building this module.

Pandas 0.18 includes a style attribute that makes dataframes pretty. When rendered in html for inclusion in an email using render, the dataframe is nicely displayed inline as html and can be saved to an html file on the local path.

yagmail is able to send an email form a notebook, but the resulting message body contains degraded versions of the html dataframe rendering, irrespective of the method with which it was added to the yagmail code.

Code below shows an example of a styled dataframe which looks nice in a notebook. It is then converted to html and attempts are made to embed the html in-line with fidelity to the original styling. All attempts fail.

import numpy as np
import pandas as pd
import yagmail

#Create Array
num = np.array([[ 0.17899619,  0.33093259,  0.2076353,   0.06130814,],
            [ 0.20392888,  0.42653105,  0.33325891,  0.10473969,],
            [ 0.17038247,  0.19081956,  0.10119709,  0.09032416,],
            [-0.10606583, -0.13680513, -0.13129103, -0.03684349,],
            [ 0.20319428,  0.28340985,  0.20994867,  0.11728491,],
            [ 0.04396872,  0.23703525,  0.09359683,  0.11486036,],
            [ 0.27801304, -0.05769304, -0.06202813,  0.04722761,],])

days = ['5 days', '10 days', '20 days', '60 days']

prices = ['AAPL', 'ADBE', 'AMD', 'AMZN', 'CRM', 'EXPE', 'FB']

#Convert Array to DataFrame
df = pd.DataFrame(num, index=prices, columns=days)

#Style the DataFrame

df_styled = df.style\
  .bar(color='#d65f5f')\
  .set_precision(2)\
  .set_caption('Set Title of the Table')

# Render the styled df in html
df_styled_html = df_styled.render()

#Save the styled/rendered html tables as a file
with open('styled_rendered.html', 'w') as f:
    f.write(df_styled_html)

#Send email

yag = yagmail.SMTP()

subject = 'Styled DataFrame in HTML Format'

contents = [df_styled_html,
        'styled_rendered.html', 
        yagmail.inline(df_styled),
        yagmail.inline(df_styled_html),
        yagmail.inline('styled_rendered.html')]


yag.send('user@domain.com', subject, contents)

When df_styled_html is passed, we get a CSS string in the body of the email. Perhaps the email code is not appplying CSS styules to the dataframe natively?

Thanks.

@kootenpv
Copy link
Owner

kootenpv commented Aug 25, 2016

I know that to apply CSS in any email, it cannot be <style> tags, but has to be like <h1 style="color:red">text</h1>. Maybe that insight helps?

Also, I think you do not want inline... Try it without using yagmail.inline, and then using an html_string. This will then get parsed as a whole and become the email message. Other option is to pass a html filepath string.

E.g.: yag.send(contents=df_styled_html). or yag.send(contents='styled_rendered.html')

If you can apply CSS onto this HTML, that's what you probably need. You might want to consider stripping \n, since they are converted to </br>

@nutcrackerhf
Copy link
Author

Thanks. Python has a built-in html escaper which can be applied to a styled/rendered html object like df_styled_rendered in the sample code above:

import html
df_styled_html_escaped = html.escape(df_styled_html)

You can then pass df_styled_html_escaped into the yagmail function using yag.send(contents=df_styled_html_escaped).

This function sends an email which begins with the appropriate <style type="text/css">. Unfortunately it is printed at the top of the email body, rather than interpreted and rendered as styled html.

@kootenpv
Copy link
Owner

Just in case it wasn't clear: it is email that does not allow <style> tags, not yagmail. So the CSS has to be on the nodes themselves rather than in a separate <style> tag. You could perhaps write a function that applies the styling onto the nodes in your html? Or am I the one misunderstanding what you've tried?

@cyung-aa
Copy link

cyung-aa commented Feb 6, 2018

Hi, I have such similar question.
The same html string with css and <style> tags can be displayed using
msg=MIMEMultipart()
...
part=MIMEText(html_string,'html',_charset="utf-8")
msg.attach(part)
smtpObj.sendmail(_user,to_list,msg.as_string())

But
yag.send(contents=html_string) doesn't work

@lisrael1
Copy link

lisrael1 commented Sep 3, 2018

like kootenpv wrote - seems like the problem is that style tags are not inline
i used 'from premailer import transform' to fix the render() output and it worked
example:
html=df.round(2).style.bar(subset=['a', 'c'], align='mid', color=['#d65f5f', '#5fba7d']).render()
html_inline=transform(html)

@kootenpv
Copy link
Owner

Just throwing it out there, this is now also possible:

yag.send(contents="test\ntest", newline_to_break=False)

Closing, but feel free to open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants