Multiple calls to .plot(): colors not correctly cycled #8242

Closed
twiecki opened this Issue Sep 11, 2014 · 4 comments

Comments

Projects
None yet
3 participants
Contributor

twiecki commented Sep 11, 2014

Versions:
Pandas 0.14.1
Matplotlib: 1.4.0

Reproduce:
Run:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

for i in range(20):
    pd.Series(np.random.rand(20)).plot(label=i)
plt.legend()

Output:
index
You can see that the colors are cycled once and then only blue (i.e. the first color) is being used.

Expected output:
index2
You can see that colors are being cycled correctly.

The expected output was produced using matplotlib's plot() command. But note that if Series.plot() was run once in the interpreter, matplotlib's plot() command produces the same errenous behavior (only plotting blue after the first cycle). It thus appears that Series.plot() sets some global matplotlib state that causes this.

Contributor

onesandzeroes commented Sep 11, 2014

I think there's something odd going on here.

    else:
        if color_type == 'default':
            colors = plt.rcParams.get('axes.color_cycle', list('bgrcmyk'))
            if isinstance(colors, compat.string_types):
                colors = list(colors)

I added a print statement in there to print the colour list after every plot, and it creates all the colours once then just sticks on blue:

['b', 'g', 'r', 'c', 'm', 'y', 'k']
['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b']
['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b', 'b']
['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b', 'b', 'b']
['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b', 'b', 'b', 'b']
['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b', 'b', 'b', 'b', 'b']
['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b', 'b', 'b', 'b', 'b', 'b']
['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b', 'b', 'b', 'b', 'b', 'b', 'b']

I don't know if I understand the matplotlib internals well enough to get any further with this.

Contributor

TomAugspurger commented Sep 11, 2014

The problem is actually coming further down:

132     if len(colors) != num_colors:                                               
133         multiple = num_colors//len(colors) - 1                                  
134         mod = num_colors % len(colors)                                          
135                                                                                 
136         colors += multiple * colors                                             
137         colors += colors[:mod]                                                  

I guess we are somehow modifying the global matplotlib rcParams...

In [1]: plt.rcParams['axes.color_cycle']
Out[1]: ['b', 'g', 'r', 'c', 'm', 'y', 'k']

In [2]: import matplotlib.pyplot as plt

In [3]: import numpy as np

In [4]: import pandas as pd

In [5]: for i in range(20):
   ...:         pd.Series(np.random.rand(20)).plot(label=i)
   ...:     

In [6]: plt.rcParams['axes.color_cycle']
Out[6]: 
['b',
 'g',
 'r',
 'c',
 'm',
 'y',
 'k',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b',
 'b']

Not sure how though.

Contributor

TomAugspurger commented Sep 11, 2014

Ahh up above we get the color cycle list from the rcParams. This list is a view of the list in the global rcParams, so we modify the global when we do

colors += multiple * colors                                             
colors += colors[:mod]                                                  

I'll do a PR when I figure out why we do that in the first place.

Contributor

TomAugspurger commented Sep 12, 2014

Should be fixed on master now. Thanks @twiecki

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment