I am using Jupyter notebook. I have DataFrames that when created are never the same length and would like to apply a list of colors I define on a unique value of a column. The DataFrames do share the same column I intend to color based on unique values. Where I am getting stuck is if the length of the DataFrame index is greater than the number of colors listed in my list I receive an error saying "IndexError: list index out of range". I would like to continue to iterate with my list of colors regardless the length of unique values in the below example, column x1.
Below I have a one off MRE that should be able to test. You will note that df3 works correctly due to column x1 having the same length of values as colors in my list whereas df4 throws an error due to column x1 having more values than colors in my list.
df1 = pd.DataFrame({'x1':['a', 'b', 'b', 'c', 'd', 'd'],
'x2':['3', '4', '8', '0', '11', '1']})
df2 = pd.DataFrame({'x1':['a', 'a', 'c', 'd', 'e', 'e', 'f', 'g', 'g', 'g', 'h'],
'x2':['0', '41', '22', '5', '19', '21', '5', '7', '8', '24', '15']})
def Color_Unique(s):
df = s.copy()
color_map = {}
Trade_Cusip_Combo_Key = df['x1'].unique()
colors_to_use = ['background-color: #ADD8E6', 'background-color: #90ee90', 'background-color: #FFD580', 'background-color: #CBC3E3', 'background-color: #D3D3D3', 'background-color: #C4A484']
for Trade_Cusip_Combo in Trade_Cusip_Combo_Key:
color_map[Trade_Cusip_Combo] = colors_to_use[0]
colors_to_use.pop(0)
for index, row in df.iterrows():
if row['x1'] in Trade_Cusip_Combo_Key:
Trade_Cusip_Combo = row['x1']
my_color = color_map[Trade_Cusip_Combo]
df.loc[index,:] = my_color
else:
df.loc[index,:] = 'background-color: '
return df
df3 = df1.style.apply(Color_Unique, axis=None)
df3
df4 = df2.style.apply(Color_Unique, axis=None)
df4
CodePudding user response:
On my system there is no IndexError. Below the IPython session using the code you have provided. Your issue seem to be caused by the fact that you assign some style to df1
and df2
before you run the code you have provided as with exact the steps in your question the function Color_Unique() won't be run at all and therefore can't cause an IndexError. Below the IPython session as evidence of what I said above. Why I write about it at all? To point out following:
Asking questions provide the entire code you had run in your session before. Restart your environment and check if you can reproduce what you have experienced if run from fresh started system before you ask a question.
Be tuned for updates to this answer helping with getting rid of the IndexError assigning colors in a cyclic way if the table length exceeds the amount of colors.
Python 3.9.13 (main, May 20 2022, 21:21:14)
Type 'copyright', 'credits' or 'license' for more information
IPython 8.0.1 -- An enhanced Interactive Python. Type '?' for help.
In [2]: import pandas as pd
In [3]: df1 = pd.DataFrame(
...: {"x1": ["a", "b", "b", "c", "d", "d"], "x2": ["3", "4", "8", "0", "11", "1"]}
...: )
...:
...:
...: df2 = pd.DataFrame(
...: {
...: "x1": ["a", "a", "c", "d", "e", "e", "f", "g", "g", "g", "h"],
...: "x2": ["0", "41", "22", "5", "19", "21", "5", "7", "8", "24", "15"],
...: }
...: )
...:
...: color_map = {}
...:
...: Trade_Cusip_Combo_Key = df["x1"].unique()
...: colors_to_use = [
...: "background-color: #ADD8E6",
...: "background-color: #90ee90",
...: "background-color: #FFD580",
...: "background-color: #CBC3E3",
...: "background-color: #D3D3D3",
...: "background-color: #C4A484",
...: ]
...:
...: for Trade_Cusip_Combo in Trade_Cusip_Combo_Key:
...: color_map[Trade_Cusip_Combo] = colors_to_use[0]
...: colors_to_use.pop(0)
...:
...: for index, row in df.iterrows():
...: if row["x1"] in Trade_Cusip_Combo_Key:
...: Trade_Cusip_Combo = row["x1"]
...: my_color = color_map[Trade_Cusip_Combo]
...: df.loc[index, :] = my_color
...: else:
...: df.loc[index, :] = "background-color: "
...: return df
In [5]: df3 = df1.style.apply(Color_Unique, axis=None)
...:
In [6]: df3
Out[6]: <pandas.io.formats.style.Styler at 0x7fb1d0793940>
In [7]: df4 = df2.style.apply(Color_Unique, axis=None)
...:
In [8]: df4
Out[8]: <pandas.io.formats.style.Styler at 0x7fb1d04acc70>
In [2]: import pandas as pd
In [3]: df1 = pd.DataFrame(
...: {"x1": ["a", "b", "b", "c", "d", "d"], "x2": ["3", "4", "8", "0", "11", "1"]}
...: )
...:
...:
...: df2 = pd.DataFrame(
...: {
...: "x1": ["a", "a", "c", "d", "e", "e", "f", "g", "g", "g", "h"],
...: "x2": ["0", "41", "22", "5", "19", "21", "5", "7", "8", "24", "15"],
...: }
...: )
...:
...: color_map = {}
...:
...: Trade_Cusip_Combo_Key = df["x1"].unique()
...: colors_to_use = [
...: "background-color: #ADD8E6",
...: "background-color: #90ee90",
...: "background-color: #FFD580",
...: "background-color: #CBC3E3",
...: "background-color: #D3D3D3",
...: "background-color: #C4A484",
...: ]
...:
...: for Trade_Cusip_Combo in Trade_Cusip_Combo_Key:
...: color_map[Trade_Cusip_Combo] = colors_to_use[0]
...: colors_to_use.pop(0)
...:
...: for index, row in df.iterrows():
...: if row["x1"] in Trade_Cusip_Combo_Key:
...: Trade_Cusip_Combo = row["x1"]
...: my_color = color_map[Trade_Cusip_Combo]
...: df.loc[index, :] = my_color
...: else:
...: df.loc[index, :] = "background-color: "
...: return df
In [5]: df3 = df1.style.apply(Color_Unique, axis=None)
...:
In [6]: df3
Out[6]: <pandas.io.formats.style.Styler at 0x7fb1d0793940>
In [7]: df4 = df2.style.apply(Color_Unique, axis=None)
...:
In [8]: df4
Out[8]: <pandas.io.formats.style.Styler at 0x7fb1d04acc70>
CodePudding user response:
You can easily loop through your list of colors, going back to the start once you reach the end, by using