0

Answering the famous question "How to get different colored lines for different plots in a single figure?" I stumbled in a behavior that puzzled me...

The problem is to get different line colors in different subplots, like this

In [29]: import numpy as np 
    ...: import matplotlib.pyplot as plt                                                  

In [30]: fig, axes = plt.subplots(2,1)                                                    

In [31]: for ax in axes.flatten(): 
    ...:     ax.plot((0,1), (0,1))                                                        

enter image description here

As you can see, both lines are Blue — I can understand that this happens because each ax has its own prop_cycle.

I can remedy the problem using an explicit color name

In [44]: fig, axes = plt.subplots(2,1)                                                    

In [45]: for ax, short_color_name in zip(axes.flatten(), 'brgkyc'): 
    ...:     ax.plot((0,1), (0,1), short_color_name)                                      

enter image description here

but if I try to reuse the same cycler object...

In [47]: my_cy = plt.rcParams['axes.prop_cycle']                                          

In [48]: for ax in axes.flatten(): 
    ...:     ax.set_prop_cycle(my_cy) 
    ...:     ax.plot((0,1), (0,1))                                                        

I get two subplots with two Blue lines...

In my understanding, what I'd like to do is impossible because the ax calls the cycler that returns an itertools.cycle that in turn actually produces the kwargs as needed, but I ask anyway because

There are more things in Matplotlib than are dreamt of in my philosophy.

gboffi
  • 22,939
  • 8
  • 54
  • 85
  • Is [this](https://stackoverflow.com/questions/53521396/how-to-implement-automatic-color-change-in-matplotlib-with-subplots/53523348#53523348) what you want to do? – ImportanceOfBeingErnest Dec 08 '18 at 11:24
  • @ImportanceOfBeingErnest More or less... As well as the poster of the question you mentioned, I'd like to delegate as much as possible to Matplotlib, but your answer is good enough. Thank you. – gboffi Dec 08 '18 at 11:48

2 Answers2

1

My recommendation in case you only have a single artist to style would be

import matplotlib.pyplot as plt

fig, axes = plt.subplots(2,2)
cycler = plt.rcParams['axes.prop_cycle']()

for i, ax in enumerate(axes.flat):
    ax.plot((0,1), (0,1), **next(cycler))

plt.show()
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
0

Prompted by this comment, I'd like to propose

...
next_shared_style = plt.rcParams['axes.prop_cycle']().__next__
for i, ax in enumerate(axes):
    ax.plot(x, y[i], **next_shared_style())

where

  • plt.rcParams['axes.prop_cycle'] is a cycler object,
  • plt.rcParams['axes.prop_cycle']() returns a itertools.cycle object and
  • next_shared_style = plt.rcParams['axes.prop_cycle']().__next__ is the __next__ method of the itertools.cycle object.

Each invocation of next(my_cycle_object_as_instantiated_by_a_cycler) returns a dictionary of parameters, to pass correctly this dictionary to a pyplot plotting command we have simply to unpack it, as in
plot(x, y[i], **next_shared_style()).

Using the whole dictionary ensures that each subplot shares the same loop over all the attributes that are controlled by the prop_cycle.

gboffi
  • 22,939
  • 8
  • 54
  • 85