1

I have a dataframe, and I would like to highlight the cells red, where the word "BBC" appears.

Looking at this SO thread and this one I tried the below:

df.style.apply(lambda x: ["background-color: red" if x == "BBC News" else "background-color: green"])

or

df.style.apply(lambda x: ["background-color: red" if v == "BBC News" else "background-color: green" for v in x], axis=None)

enter image description here

But this doesn't color anything. FWIW, I don't know what the x or v are in the examples I used. I assume x is a cell, and v would be a part of the cell?

How can I conditinally format cells? I'd also be adding others, i.e. if "CNN" appears in a cell, color yellow, etc.

Edit: I tried simply df.style.apply(lambda x: ["background-color: green"]) and nothing happened (same if I used #ff0000 or rgb(0,0,255)).

To be explicit, I'm doing:

df.style.apply(lambda x: ["background-color: #ff0000" if v['newsSource'] == "BBC News" else "background-color: #ffff00"], axis=None)
df.to_html("styletest.html")

So I want the coloring visible in the HTML DOCUMENT not the dataframe itself necessarily.

BruceWayne
  • 22,923
  • 15
  • 65
  • 110
  • Could you try color code instead of string – nerdicsapo Jul 25 '18 at 14:40
  • @NerdicSapo - Do you mean hex, i.e. #FFFFF? I tried replacing `red` with `#ff0000` and `green` with `#ffff00` (just to test if it wokrs), and no colors show. – BruceWayne Jul 25 '18 at 14:41
  • You want to change check first column, which is 'newsSource'. You need to access column. – nerdicsapo Jul 25 '18 at 14:45
  • @rahlf23 - Where does that go, `lamba x['newsSource']`? I tried adding that to [...if x['newsSource'] == "BBC News"...]` but nothing changed. It may help to state that while typically I am pretty good at understanding list comprehensions, I have no idea at all what the `x` or `v` are in my second example, so clarifying that might help my understanding. Edit: Just saw your edited comment. One second let me apply. – BruceWayne Jul 25 '18 at 14:48
  • @BruceWayne x is each column/row and v is each element within? Also are you looking for `v == "BBC News"` for just `"BBC" in v`? – AsheKetchum Jul 25 '18 at 14:50
  • @AsheKetchum - Preferably, I'd like to search for `[word] in v`, so I don't have to know the exact name. I have no idea what the `x` and `v` are, I was just following other examples I found. :/ – BruceWayne Jul 25 '18 at 14:51
  • @rahlf23 - Thanks for the edit, I tried the code but still no coloring :/ – BruceWayne Jul 25 '18 at 14:51
  • Let's discuss (hopefully this link works): https://chat.stackoverflow.com/rooms/176733/pandas-discussion – rahlf23 Jul 25 '18 at 14:56

3 Answers3

4

Alright, this should do it:

import pandas as pd

df = pd.DataFrame([['BBC News','something','Test1'],
                    ['The Wall Street Journal','something else','Test2'],
                    ['BBC News','something else entirely','Test3']],
                    columns=['newsSource','description','title'])

html = df.style.apply(lambda x: ["background: red" if 'BBC' in x['newsSource'] and idx==0 else "" for idx, v in enumerate(x)], axis = 1).set_table_attributes('border="1" class="dataframe table table-hover table-bordered"').render()

with open('test.html', 'w') as f:
    f.write(html)

Explanation:

The lambda operator allows you to apply the following ["background: red" if 'BBC' in x['newsSource'] and idx==0 else "" for idx, v in enumerate(x)]to every row of your df (specified by axis=1), where x is each individual row of your df.

In English, this means change to "background: red" if the string 'BBC' is contained in x['newsSource'], i.e. the 'newsSource' column of the row x of df. The extra logic specifying idx==0 means only the first cell of that row x, for which we have to enumerate(x) in order to track the current column index idx. Otherwise, do not change the background color, using else "". Hope that's clear!

rahlf23
  • 8,869
  • 4
  • 24
  • 54
  • Yeah, that works. Column B and C are highlighted red. Now, we need to apply that logic to text instead of numbers :D – BruceWayne Jul 25 '18 at 15:47
  • Hayoooo - the whole row highlights red! We're getting somewhere! Now, how could I make just the cell the word appears in red? – BruceWayne Jul 25 '18 at 15:54
  • oh, you wanted to display it in the html? – AsheKetchum Jul 25 '18 at 15:55
  • 1
    @AsheKetchum - What do you mean? Yeah, I was referring to the HTML. Can you color the **dataframe** itself somehow, which may not reflect when doing `to_html()`?? – BruceWayne Jul 25 '18 at 15:59
  • 1
    @BruceWayne Yeah, like if you just say df.style.apply(highlight, axis=1) it prints the DataFrame with the desired coloring, for an interactive environment at least – AsheKetchum Jul 25 '18 at 16:00
  • Thanks so much @rahlf23! This works. Now, it's a little much to ask, but could you maybe break down that lambda function, in "english"? I'm trying to make sense of it. (Mainly, so I can learn how to use this for other words/columns). Yay!! – BruceWayne Jul 25 '18 at 16:02
  • (@rahlf23 - I get the `set_table_attributes` part mostly, so no need to explain that. It's the lambda craziness that I don't quite get :P) – BruceWayne Jul 25 '18 at 16:06
  • 1
    Thanks **so much** for your help! (Ash too!) – BruceWayne Jul 25 '18 at 16:23
2

Let me know if something like this works?

def highlight_txt(s, txt):

    has_bbc = s.apply(lambda x: '')
    bbc = s.index.tolist().index('newsSource')
    has_bbc[bbc] = 'background-color: yellow' if txt in s[bbc] else 'background-color: green'

    return has_bbc

df.style.apply(lambda x: highlight_txt(x, 'BBC', axis=1))
AsheKetchum
  • 1,098
  • 3
  • 14
  • 29
  • Nothing happend :( FYI if I call `type(df)` just before the `.apply` line, I do get `` Edit: Still nothing, after the edit – BruceWayne Jul 25 '18 at 15:21
  • k try again? I forgot to change the `if 'a' in s[bbc]` to `if 'BBC' in s[bbc]` – AsheKetchum Jul 25 '18 at 15:22
  • Still nothing :( – BruceWayne Jul 25 '18 at 15:43
  • I feel like the logic should be right now xD, it worked for my simple df `df = pd.DataFrame(columns=['a','b','c'], data=[['b', 'a', 'd'], ['c', 'x', 'f'], ['b', 's', 'w']])` – AsheKetchum Jul 25 '18 at 15:44
  • That doesn't highlight anything for me. [Screenshot of my code](https://i.stack.imgur.com/yeOyr.jpg) (sorry it's a screenshot, but I don't know a better way to show the code) – BruceWayne Jul 25 '18 at 15:51
0

I would separate this to a function for clarity, and then iterate over the rows:

def highlight_cell(row):
    background = []
    for cell in row:
        color = 'background-color: green'
        if 'BBC' in cell:
            color = 'background-color: red'
        elif 'CNN' in cell:
            color = 'background-color: yellow'
        background.append(color)
    return background

df.style.apply(highlight_cell, axis=1)
jack6e
  • 1,512
  • 10
  • 12