for my html representation of a pandas dataframe (python), I'd like to create something that resembles as much as possible the image below (created with Excel), that is, given a sequence of numbers, create INSIDE A TABLE, some horizontal bar charts that become green if the value is greater than zero, red if they are below zero and with the "zero" point in the axis which dynamically rescales according to the data provided. the closest I got to was by using pandas native instruments is given by the code below (http://pandas.pydata.org/pandas-docs/stable/style.html)

#done in Jupyter
from pandas import DataFrame
df = pd.DataFrame([-0.02, 0.03, 0.04, -0.05], columns=['A'])
more_than_zero = df.loc[df.loc[:,'A'] >= 0].index.values.tolist()
less_than_zero = df.loc[df.loc[:,'A'] < 0].index.values.tolist()
df.style.bar(subset=pd.IndexSlice[more_than_zero,'A'], color='#d65f5f')
#df.style.bar(subset=pd.IndexSlice[less_than_zero, 'B'], color='#7fff00')
Update: This answer lead to a pull request pandas-dev/pandas#14757 that got accepted in Pandas v0.20.0. The documentation can be found on Pandas website at style.html#Bar-charts
There's no way to do this out of the box using pandas right now (I'll try to implement that soon), but for now here's a monkey-patching solution:
def _bar_center_zero(self, s, color_positive, color_negative, width):
# Either the min or the max should reach the edge (50%, centered on zero)
m = max(abs(s.min()),abs(s.max()))
normed = s * 50 * width / (100 * m)
base = 'width: 10em; height: 80%;'
attrs_neg = (base+ 'background: linear-gradient(90deg, transparent 0%, transparent {w}%, {c} {w}%, '
'{c} 50%, transparent 50%)')
attrs_pos = (base+ 'background: linear-gradient(90deg, transparent 0%, transparent 50%, {c} 50%, {c} {w}%, '
'transparent {w}%)')
return [attrs_pos.format(c=color_positive, w=(50+x)) if x > 0
else attrs_neg.format(c=color_negative, w=(50+x))
for x in normed]
def bar_excel(self, subset=None, axis=0, color_positive='#5FBA7D',
color_negative='#d65f5f', width=100):
"""
Color the background ``color`` proptional to the values in each column.
Excludes non-numeric data by default.
.. versionadded:: 0.17.1
Parameters
----------
subset: IndexSlice, default None
a valid slice for ``data`` to limit the style application to
axis: int
color_positive: str
color_negative: str
width: float
A number between 0 or 100. The largest value will cover ``width``
percent of the cell's width
Returns
-------
self : Styler
"""
#subset = _maybe_numeric_slice(self.data, subset)
#subset = _non_reducing_slice(subset)
self.apply(self._bar_center_zero, axis=axis, subset=subset,
color_positive=color_positive, color_negative=color_negative,
width=width)
return self
Monkey-patch this to the Styler class:
pd.formats.style.Styler._bar_center_zero = _bar_center_zero
pd.formats.style.Styler.bar_excel = bar_excel
Now you can use it:
df = pd.DataFrame([-0.02, 0.03, 0.04, -0.05], columns=['A'])
df.style.bar_excel(color_positive='#5FBA7D', color_negative='#d65f5f')

I since then created a pull request on GitHub where I implemented this as well as the option of centering 'dynamically' (align='mid').
The resulting bar you can get by specifying options align and depending on the type of your data are represented below:

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With