-
-
Notifications
You must be signed in to change notification settings - Fork 18k
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
ENH: Conditional HTML Formatting #10250
Conversation
@TomAugspurger what's the status on this (looks interesting). do you have some issue references? how generic is this |
Haven't put any time in to it. This is something that I could start in another library and be pulled in to pandas if people think it's useful.
|
638bd3e
to
0adaa40
Compare
@@ -1228,6 +1229,218 @@ def _write_hierarchical_rows(self, fmt_values, indent): | |||
nindex_levels=frame.index.nlevels) | |||
|
|||
|
|||
|
|||
class StyleFormatter(object): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's make a separate module (.style)
I've updated the notebook here: http://nbviewer.ipython.org/github/pydata/pandas/blob/0f0ba429180c27b4ae3cb21f6b343db46af69397/style.ipynb Would be curious to hear people's thoughts before I put too much more time into it. Specifically on
No need to read into the messy implementation yet. |
@TomAugspurger I think also adding some text formatting things would be nice (e.g. float formatting) in the example |
Sure. That could be a keyword argument to the Styler constructor. Something like
gives Doing that at the constructor level separates the two types of styling being done. python's formatting for the string vs. the CSS property: values pairs. |
actually I realize that should just use .round(2).style but was thinking that an alignment filter might be nice in that case eg .round(2).style.align_right() |
We can actually support non-conditional formattings (like (df.round(2)
.style
.color_bg_range(cmap='viridis')
.highlight_null(null_color='red')
.set_properties(**{"color": "#f8f8fa", "text-align": 'center', "width": '10em'})
.render()) We might want to support a |
I don't think u need the .render() any longer |
course this would be straightforward to hook up to some ipython widgets ..... eg maybe a row and column slider for colors |
Just pushed a quick update. Notebook: http://nbviewer.ipython.org/github/pydata/pandas/blob/a7d730f30d87027464cc1747b38a844ba8d09fe3/style.ipynb Currently working on
Supporting slices is tricky because our state is a dict mapping Table styling is just additional styling applied to the table as a whole, instead of individual cells. Pretty easy to do, it'll probably just be a dictionary you pass in when making the Should have some time on Saturday. |
This is awesome. It'll be a step change for us in using IPython Notebooks to show data, rather than writing out to Excel and doing formatting there. To put some weight behind the slices - there are a couple of concepts there:
|
@MaximilianR thanks for the comments. Re the first one, that coloring is done relative to the column. That's how
and use that with
Agreed, I'd say it's necessary. At the very least, I have to implement it so that errors aren't thrown if you have a DataFrame with a non-numeric column :) I'm also leaning towards just punting on non-unique indexes for now. I'll try to get some documentation relatively soon. I think things are to the point where the overall interaction is stable. |
This is really cool. My first impression is that the colors play too prominent a role in the styles that I see here. They tend to dominate over the numerical information. I wonder if more subtle shading / using less of the dynamic range would provide the same visual hints while not dominating the overall effect. However, as a disclaimer, IANAD (I am not a designer) |
Thanks. Agreed entirely about the colors. I'm 99% sure that there's a parameter you can pass to the matplotlib color converter or color map to control what percent of the range it uses ( |
It was a minor nit relative to the technical merits here. Please do ignore for now. |
I think you bring up a good point though. The One Thing I want to get right here is providing a flexible framework for people to build on. I'm hopeful that another library will be built that does more / better actual styling. Our defaults need to just be not awful :) |
This is really great to see. I have been doing a lot of this by hand. Some thoughts:
|
The DataFrame editor in Spyder IDE may be of interest as far as styling: https://github.com/spyder-ide/spyder/blob/master/spyderlib/widgets/variableexplorer/dataframeeditor.py |
Ok, now I'm really going to get documentation written soon, now that there's broader interest.
I want this too. From a technical standpoint it will be easy to add. I haven't found a nice way to do this from a user's point of view yet. It's on my TODO list, but will be a little latter.
Can you expand on this? I'm not sure what you mean.
Good idea, I'll check out how that works. |
Got slicing to work, but I've had to give up support for duplicates in the Index. I think that's a fair trade for now. ¯_(ツ)_/¯ And hooking up to widgets is easy and fun! |
Nice one! It's cool to think about this eventually playing nicely with pivottable. |
Potentially, I’m not familiar with that. This will at least give you classes like the row or column number that you can select and style.
|
a1e5aa7
to
f831a0b
Compare
Hi everyone, I've uploaded a first pass of the docs as a notebook here: http://nbviewer.ipython.org/gist/TomAugspurger/841a9dc2816853824ce1 I'll be iterating on that quite a bit, but it gives a good overview of what's capable. You should at least skim to the end :) Speaking of docs, I think we'll need to do some tinkering with sphinx to get this working. And my next biggish item to fix is styling of Indexes / column headers. My current best idea is dedicated methods |
@TomAugspurger I think it would be intuitive to simply do df.style.index.apply(...) or whatever (might need a slight modification to make this work, maybe a subclass) |
""" | ||
return self._todo | ||
|
||
def set(self, styles, table_styles=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you should accept any other args, except styles
here. makes it confusing otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe call this .import
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keyword :) I used .set
, I think because that's what seaborn uses. There's also matplotlib's style.use
. I might like that better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahh, I like .use
better., actually these should be named I think, e.. what I really want to do is:
pd.options.display.style = 'cool'
(and as a context manager, etc).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
o maybe export as a a tuple/dict? e.g. Styler.export('cool')
-> ('cool',.........)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And the desire to support something like pd.options.display.style
is why I accept the table_styles
kwarg in .set
/ .use
. That way you can bundle things like :hover
etc. Otherwise you have to .use('cool').set_table_styles([hover, ...])
. We could package the applied styles + table_styles into some data structure with a name and stuff; just kept it simple for now..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shoot, I’ve built up an asymmetry between .export
and .use
with this. Going to push on this issue for now and just accept styles
in .use
like you suggested I think. Then we’ll figure out the best API when we hook things up to pd.options
(0.18 I think).
On Nov 15, 2015, at 10:58 AM, Jeff Reback notifications@github.com wrote:
In pandas/core/style.py #10250 (comment):
return self
- def export(self):
"""
Export the styles to applied to the current Styler.
Can be applied to a second style with `.set`.
.. versionadded:: 0.17.1
Returns
styles: list
"""
return self._todo
- def set(self, styles, table_styles=None):
o maybe export as a a tuple? e.g. Styler.export('cool') -> ('cool',.........)—
Reply to this email directly or view it on GitHub https://github.com/pydata/pandas/pull/10250/files#r44874507.
I think I simply include the rendered html (from nbconvert) in the docs themselves eg u render at doc build time in make.py then include as a inline ref u can even split the notebook examples up a bit then style.rst can simply show these rendered examples |
depending on the data within, by using the ``.style`` property. | ||
This is a property on every object that returns a ``Styler`` object, which has | ||
useful methods for formatting and displaying DataFrames. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realized that if you are going to render the notebook, then putting it in doc/source
where you had it is prob correct. sorry. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok sure
c948c7a
to
0dc2ba0
Compare
@jreback added a small entry to whatsnews. Going to go through your comments again (thanks for reviewing btw!) and another glance over everything. But are you cool merging this sometime today and following up with remaining issues? |
it's cool with merging today I'll look at comments as well |
0dc2ba0
to
702d63e
Compare
OK then, merging. I'll start a followup issue as well. |
ENH: Conditional HTML Formatting
whoo hoo! thanks Tom! |
Thanks for reviewing & feedback. I'm excited to see what people who actually know CSS can do with this. |
thank you Tom! |
👍 |
+1 Thanks for putting this together @TomAugspurger! |
Is there anyway to apply a class to a cell instead of setting its properties? I.e. I would like to transform a table like:
to:
and define the css of the class |
@dov at the moment, no. It wouldn't be hard to add a |
Has it ever done by someone..? |
I must have missed that. No, I never opened such an issue. I'm not even sure what @TomAugspurger meant. What |
I guess what @TomAugspurger meant was that just as as use styler functions to add styles, we may be able to easily add function(s) that allow adding classes using similar methods. .set_class(classes, subset=None) is a hypothetical API method that may be named so to allow such functionality. I really needed it but I could not find one in current pandas, unless I don't know enough to be sure. |
@TomAugspurger unless someone is working on it, I'd like to working on adding the function - please let me know. |
Might want to open an issue first to discuss, unless it's likely to be a
simple / uncontroversial feature.
…On Wed, Jun 24, 2020 at 1:28 PM Jihwan Song ***@***.***> wrote:
@TomAugspurger <https://github.com/TomAugspurger> unless someone is
working on it, I'd like to working on adding the function - please let me
know.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#10250 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAKAOIS7SRQTQBIUIKAWMG3RYJATTANCNFSM4BGSHORQ>
.
|
closes #3190
closes #4315
Not close to being done, but I wanted to put this here before the meeting. Maybe someone will have a chance to check it out.
http://nbviewer.ipython.org/github/TomAugspurger/pandas/blob/638bd3e361633a4c446ee02534e07b8a9332258a/style.ipynbhttps://github.com/TomAugspurger/pandas/blob/stylely/style.ipynblatest example notebook