18

I am trying to plot some data in pandas and the inbuilt plot function conveniently plots one line per column. What I want to do is to manually assign each line a color based on a classification I make.

The following works:

df = pd.DataFrame({'1': [1, 2, 3, 4], '2': [1, 2, 1, 2]})
s = pd.Series(['c','y'], index=['1','2'])
df.plot(color = s)

But when my indices are integers it no longer works and throws as KeyError:

df = pd.DataFrame({1: [1, 2, 3, 4], 2: [1, 2, 1, 2]})
s = pd.Series(['c','y'], index=[1,2])
df.plot(color = s)

The way I understand it is that when an integer index is used it somehow has to start from 0. That is my guess since the following works as well:

df = pd.DataFrame({0: [1, 2, 3, 4], 1: [1, 2, 1, 2]})
s = pd.Series(['c','y'], index=[1,0])
df.plot(color = s)

My question is:

  • What is happening here?
  • Assuming I have an integer index that does not start from 0 or is not formed of successive numbers, how can I make this work without having to convert the index to string or reindex starting from 0?

EDIT:

I realised that even in the first case, the code doesn't do what I expected it to do. It seems like pandas matches the index of DataFrame and Series only if both are integer indices starting from 0. If that isn't the case, a KeyError is thrown or if the index is a str the order of the elements is used.

Is this correct? And is there a way to match the Series and DataFrame indices? Or do I have to make sure I pass a list of colours in the right order?

GebitsGerbils
  • 365
  • 1
  • 4
  • 10

3 Answers3

21

What is happening here?

The keyword argument color is inherited from matplotlib.pyplot.plot(). The details in the documentation don't make it clear that you can put in a list of colors when plotting. Given that color is a keyword argument from matplotlib, I'd recommend not using a Pandas Series to hold the color values.

How can I make this work?

Use a list instead of a Series. If you were using a Series with an index meant to match the columns of your DataFrame to specific colors, you will need to sort the Series first. If the columns are not in order, you will need to sort the columns as well.

# Option 1
s = s.sort_index()
df.plot(color = s.values) # as per Fiabetto's answer

# Option 2
df.plot(color = ['c', 'y']) # other method
Alessandro Mariani
  • 1,181
  • 2
  • 10
  • 26
thecircus
  • 905
  • 7
  • 15
  • I ended up sorting both the Series and the DataFrame and then turned the Series into a list as suggested. This works without a problem, but I was hoping there was a more elegant way, but I can see how there can't be if the color keyword corresponds to matplotlibs (which obviously knows nothing about Series). – GebitsGerbils Sep 11 '15 at 15:24
  • 1
    Yeah, unfortunately Pandas is just a wrapper to matplotlib. matplotlib allows the user to to almost anything, but it can get really messy. – thecircus Sep 11 '15 at 18:07
10

To set color for each line you can use the parameter style. For example:

df = pd.DataFrame({'A': [1, 2, 4], 'B': [1, 3, 9]})
df.plot(style={'A': 'r', 'B': 'g'})

enter image description here

Using the shortcut string notation in the form marker|line|color you can also set marker and line types:

df = pd.DataFrame({'A': [1, 2, 4], 'B': [1, 3, 9]})
df.plot(style={'A': '*:r', 'B': '+--g'})

enter image description here

Mykola Zotko
  • 15,583
  • 3
  • 71
  • 73
5

Try:

df.plot(color = s.values)

this will assign the colors no matter the scale of the index.

EDIT:

I tried with three columns:

df = pd.DataFrame({'1': [1, 2, 3, 4], '2': [1, 2, 1, 2], '3': [4, 3, 2, 1]})
s = pd.Series(['c','y','r'], index=[1,3,2])
df.plot(color = s.sort_index().values)

and sorting the Series it works.

Fabio Lamanna
  • 20,504
  • 24
  • 90
  • 122