I want to use some pandas style resources and I want to hide table indexes on streamlit.
I tryed this:
import streamlit as st
import pandas as pd
table1 = pd.DataFrame({'N':[10, 20, 30], 'mean':[4.1, 5.6, 6.3]})
st.dataframe(table1.style.hide_index().format(subset=['mean'],
decimal=',', precision=2).bar(subset=['mean'], align="mid"))
but regardless the .hide_index() I got this:
Ideas to solve this?
Documentation for st.dataframe shows "Styler support is experimental!"
and maybe this is the problem.
But I can get table without index if I use .to_html() and st.write()
import streamlit as st
import pandas as pd
df = pd.DataFrame({'N':[10, 20, 30], 'mean':[4.1, 5.6, 6.3]})
styler = df.style.hide_index().format(subset=['mean'], decimal=',', precision=2).bar(subset=['mean'], align="mid")
st.write(styler.to_html(), unsafe_allow_html=True)
#st.write(df.to_html(index=False), unsafe_allow_html=True)
Another option is using a CSS selector to remove the index column. Like explained in the docs, you can do the following with st.table:
# import packages
import streamlit as st
import pandas as pd
# table
table1 = pd.DataFrame({'N':[10, 20, 30], 'mean':[4.1, 5.6, 6.3]})
# CSS to inject contained in a string
hide_table_row_index = """
<style>
thead tr th:first-child {display:none}
tbody th {display:none}
</style>
"""
# Inject CSS with Markdown
st.markdown(hide_table_row_index, unsafe_allow_html=True)
# Display a static table
st.table(table1.style.format(subset=['mean'],
decimal=',', precision=2).bar(subset=['mean'], align="mid"))
Output:
As you can see the index is gone. Keep in mind that the table function takes the full page.
Related
I have value_count output data for a single column that I would like to feed into a table and format nicely. I would like to bold the headings, have "alternating colors" for the rows, change the font to "serif", and italicize the main column. Kind of like this.
I thought I found something applicable, but I do not know how to apply it to my data (or perhaps it is not suited for what I want to achieve).
I found "table styles" with the following example:
df4 = pd.DataFrame([[1,2],[3,4]])
s4 = df4.style
props = 'font-family: "Times New Roman", Times, serif; color: #e83e8c; font-size:1.3em;'
df4.style.applymap(lambda x: props, subset=[1])
Here is my code on its own. Please note I had to first split my data (here) so that I could properly count to end up with the value_count output data. These are a few libraries I have been working with (but there could be a few unnecessary ones in here).
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import warnings
warnings.filterwarnings('ignore')
#access file
data = pd.read_csv('E:/testing_data.csv')
supplies = pd.DataFrame(data)
supplies.Toppings = supplies.Toppings.str.split('\r\n')
supplies = supplies.explode('Toppings').reset_index(drop=True)
supplies.Toppings.value_counts(normalize=True).mul(100).round(1).astype(str) + '%'
Please be as specific as possible as I am still getting used to Python terms. Thank you.
I need to color specific columns in the table and convert it to html. I know it's possible to apply pandas styling to required subsets of data; for example, the next code snippet seems to work just fine. But the problem is that I need to set the same styling using bgcolor html attribute, not CSS. And I have found only Styler.set_table_attributes, which doesn't really help in my case. My current approach: I'm converting the html obtained from pandas to BeautifulSoup and adding attributes there, but it's not really convenient.
import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame(np.random.randn(10,4), columns=['A','B','C','D'])
st = df.style
def highlight(c):
color = 'green' if (c > 0) else 'red'
return f'background-color:{color}'
st.applymap(highlight, subset=['C', 'D'])
with open('out.html','w') as f:
f.write(str(st.to_html()))
# how i'm doing this now:
from bs4 import BeautifulSoup
res = BeautifulSoup(df.to_html(index=False), features='html.parser')
for header in ['C', 'D']:
index = df.columns.get_loc(header)
for tr in res.table.tbody.select('tr'):
td = tr.select('td')[index]
c = float(td.text)
td.attrs['bgcolor'] = 'green' if (c > 0) else 'red'
with open('out2.html','w') as f:
f.write(str(res))
You can set the bgcolor attribute using pandas styling by defining a custom function that returns the bgcolor attribute in an HTML style tag. You can then use this function with the Styler.applymap() method to apply the styling to the required subset of data.
Example:
import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame(np.random.randn(10,4), columns=['A','B','C','D'])
st = df.style
def highlight(c):
color = 'green' if (c > 0) else 'red'
return f'bgcolor: {color}'
st.applymap(highlight, subset=['C', 'D'])
with open('out.html','w') as f:
f.write(st.to_html())
The render() method of the Styler object will return the styled DataFrame as an HTML string with the bgcolor attribute set using the style tag.
print('http://google.com') outputs a clickable url.
How do I get clickable URLs for pd.DataFrame(['http://google.com', 'http://duckduckgo.com']) ?
If you want to apply URL formatting only to a single column, you can use:
data = [dict(name='Google', url='http://www.google.com'),
dict(name='Stackoverflow', url='http://stackoverflow.com')]
df = pd.DataFrame(data)
def make_clickable(val):
# target _blank to open new window
return '<a target="_blank" href="{}">{}</a>'.format(val, val)
df.style.format({'url': make_clickable})
(PS: Unfortunately, I didn't have enough reputation to post this as a comment to #Abdou's post)
Try using pd.DataFrame.style.format for this:
df = pd.DataFrame(['http://google.com', 'http://duckduckgo.com'])
def make_clickable(val):
return '{}'.format(val,val)
df.style.format(make_clickable)
I hope this proves useful.
#shantanuo : not enough reputation to comment.
How about the following?
def make_clickable(url, name):
return '{}'.format(url,name)
df['name'] = df.apply(lambda x: make_clickable(x['url'], x['name']), axis=1)
I found this at How to Create a Clickable Link(s) in Pandas DataFrame and JupyterLab which solved my problem:
HTML(df.to_html(render_links=True, escape=False))
from IPython.core.display import display, HTML
import pandas as pd
# create a table with a url column
df = pd.DataFrame({"url": ["http://google.com", "http://duckduckgo.com"]})
# create the column clickable_url based on the url column
df["clickable_url"] = df.apply(lambda row: "<a href='{}' target='_blank'>{}</a>".format(row.url, row.url.split("/")[2]), axis=1)
# display the table as HTML. Note, only the clickable_url is being selected here
display(HTML(df[["clickable_url"]].to_html(escape=False)))
I am using iPython notebook. When I do this:
df
I get a beautiful table with cells. However, if i do this:
df1
df2
it doesn't print the first beautiful table. If I try this:
print df1
print df2
It prints out the table in a different format that spills columns over and makes the output very tall.
Is there a way to force it to print out the beautiful tables for both datasets?
You'll need to use the HTML() or display() functions from IPython's display module:
from IPython.display import display, HTML
# Assuming that dataframes df1 and df2 are already defined:
print "Dataframe 1:"
display(df1)
print "Dataframe 2:"
display(HTML(df2.to_html()))
Note that if you just print df1.to_html() you'll get the raw, unrendered HTML.
You can also import from IPython.core.display with the same effect
from IPython.display import display
display(df) # OR
print df.to_html()
This answer is based on the 2nd tip from this blog post: 28 Jupyter Notebook tips, tricks and shortcuts
You can add the following code to the top of your notebook
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
This tells Jupyter to print the results for any variable or statement on it’s own line. So you can then execute a cell solely containing
df1
df2
and it will "print out the beautiful tables for both datasets".
I prefer not messing with HTML and use as much as native infrastructure as possible. You can use Output widget with Hbox or VBox:
import ipywidgets as widgets
from IPython import display
import pandas as pd
import numpy as np
# sample data
df1 = pd.DataFrame(np.random.randn(8, 3))
df2 = pd.DataFrame(np.random.randn(8, 3))
# create output widgets
widget1 = widgets.Output()
widget2 = widgets.Output()
# render in output widgets
with widget1:
display.display(df1)
with widget2:
display.display(df2)
# create HBox
hbox = widgets.HBox([widget1, widget2])
# render hbox
hbox
This outputs:
In order to show the DataFrame in Jupyter Notebook just type:
display(Name_of_the_DataFrame)
for example:
display(df)
It seems you can just display both dfs using a comma in between in display.
I noticed this on some notebooks on github. This code is from Jake VanderPlas's notebook.
class display(object):
"""Display HTML representation of multiple objects"""
template = """<div style="float: left; padding: 10px;">
<p style='font-family:"Courier New", Courier, monospace'>{0}</p>{1}
</div>"""
def __init__(self, *args):
self.args = args
def _repr_html_(self):
return '\n'.join(self.template.format(a, eval(a)._repr_html_())
for a in self.args)
def __repr__(self):
return '\n\n'.join(a + '\n' + repr(eval(a))
for a in self.args)
display('df', "df2")
You can use markdown to create a table. You'll be asked to install tabulate package first if it is not yet available.
from IPython.display import display, Markdown
display(Markdown(df.to_markdown()))
To display dataframes contained in a list:
dfs = [df1, df2]
display(*dfs)
From my other answer,
if you want to using option, you can use context manager combining the display:
from IPython.display import display
with pd.option_context('precision', 3):
display(df1)
display(df2)
I am using iPython notebook. When I do this:
df
I get a beautiful table with cells. However, if i do this:
df1
df2
it doesn't print the first beautiful table. If I try this:
print df1
print df2
It prints out the table in a different format that spills columns over and makes the output very tall.
Is there a way to force it to print out the beautiful tables for both datasets?
You'll need to use the HTML() or display() functions from IPython's display module:
from IPython.display import display, HTML
# Assuming that dataframes df1 and df2 are already defined:
print "Dataframe 1:"
display(df1)
print "Dataframe 2:"
display(HTML(df2.to_html()))
Note that if you just print df1.to_html() you'll get the raw, unrendered HTML.
You can also import from IPython.core.display with the same effect
from IPython.display import display
display(df) # OR
print df.to_html()
This answer is based on the 2nd tip from this blog post: 28 Jupyter Notebook tips, tricks and shortcuts
You can add the following code to the top of your notebook
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
This tells Jupyter to print the results for any variable or statement on it’s own line. So you can then execute a cell solely containing
df1
df2
and it will "print out the beautiful tables for both datasets".
I prefer not messing with HTML and use as much as native infrastructure as possible. You can use Output widget with Hbox or VBox:
import ipywidgets as widgets
from IPython import display
import pandas as pd
import numpy as np
# sample data
df1 = pd.DataFrame(np.random.randn(8, 3))
df2 = pd.DataFrame(np.random.randn(8, 3))
# create output widgets
widget1 = widgets.Output()
widget2 = widgets.Output()
# render in output widgets
with widget1:
display.display(df1)
with widget2:
display.display(df2)
# create HBox
hbox = widgets.HBox([widget1, widget2])
# render hbox
hbox
This outputs:
In order to show the DataFrame in Jupyter Notebook just type:
display(Name_of_the_DataFrame)
for example:
display(df)
It seems you can just display both dfs using a comma in between in display.
I noticed this on some notebooks on github. This code is from Jake VanderPlas's notebook.
class display(object):
"""Display HTML representation of multiple objects"""
template = """<div style="float: left; padding: 10px;">
<p style='font-family:"Courier New", Courier, monospace'>{0}</p>{1}
</div>"""
def __init__(self, *args):
self.args = args
def _repr_html_(self):
return '\n'.join(self.template.format(a, eval(a)._repr_html_())
for a in self.args)
def __repr__(self):
return '\n\n'.join(a + '\n' + repr(eval(a))
for a in self.args)
display('df', "df2")
You can use markdown to create a table. You'll be asked to install tabulate package first if it is not yet available.
from IPython.display import display, Markdown
display(Markdown(df.to_markdown()))
To display dataframes contained in a list:
dfs = [df1, df2]
display(*dfs)
From my other answer,
if you want to using option, you can use context manager combining the display:
from IPython.display import display
with pd.option_context('precision', 3):
display(df1)
display(df2)