Est-il possible d'interroger l'état actuel du cycle de couleurs matplotlib? En d'autres termes, y a-t-il une fonction get_cycle_state
qui se comportera de la manière suivante?
>>> plot(x1, y1)
>>> plot(x2, y2)
>>> state = get_cycle_state()
>>> print state
2
Où je m'attends à ce que l'état soit l'indice de la prochaine couleur qui sera utilisée dans un tracé. Sinon, s'il retournait la couleur suivante ("r" pour le cycle par défaut dans l'exemple ci-dessus), ce serait bien aussi.
python
matplotlib
mwaskom
la source
la source
Réponses:
Accéder à l'itérateur du cycle de couleurs
Il n'y a pas de méthode "face à l'utilisateur" (aka "public") pour accéder à l'itérateur sous-jacent, mais vous pouvez y accéder via des méthodes "privées" (par convention). Cependant, vous ne pouvez pas obtenir l'état d'un
iterator
sans le changer.Définition du cycle de couleur
Mise à part rapide: Vous pouvez définir le cycle couleur / propriété de différentes manières (par exemple
ax.set_color_cycle
dans les versions <1.5 ouax.set_prop_cycler
dans> = 1.5). Jetez un œil à l' exemple ici pour la version 1.5 ou supérieure , ou au style précédent ici .Accéder à l'itérateur sous-jacent
Cependant, bien qu'il n'y ait pas de méthode publique pour accéder à l'itérable, vous pouvez y accéder pour un objet axes donné (
ax
) via l'_get_lines
instance de classe d'assistance.ax._get_lines
est une touche qui porte un nom déroutant, mais c'est la machinerie des coulisses qui permet à laplot
commande de traiter toutes les manières étranges et variées quiplot
peuvent être appelées. Entre autres choses, c'est ce qui garde une trace des couleurs à attribuer automatiquement. De même, ilax._get_patches_for_fill
faut contrôler le cycle des couleurs de remplissage par défaut et des propriétés de patch.Dans tous les cas, le cycle de couleur itérable
ax._get_lines.color_cycle
concerne les lignes et lesax._get_patches_for_fill.color_cycle
patchs. Sur matplotlib> = 1.5, cela a changé pour utiliser lacycler
bibliothèque , et l'itérable est appelé à laprop_cycler
place decolor_cycle
et donnedict
des propriétés au lieu d'une seule couleur.Dans l'ensemble, vous feriez quelque chose comme:
import matplotlib.pyplot as plt fig, ax = plt.subplots() color_cycle = ax._get_lines.color_cycle # or ax._get_lines.prop_cycler on version >= 1.5 # Note that prop_cycler cycles over dicts, so you'll want next(cycle)['color']
Vous ne pouvez pas afficher l'état d'un
iterator
Cependant, cet objet est un "nu"
iterator
. Nous pouvons facilement obtenir l'élément suivant (par exemplenext_color = next(color_cycle)
, mais cela signifie que la couleur suivante est celle qui sera tracée. De par sa conception, il n'y a aucun moyen d'obtenir l'état actuel d'un itérateur sans le changer.Dans
v1.5
ou plus, il serait bien d'obtenir l'cycler
objet utilisé, car nous pourrions en déduire son état actuel. Cependant, l'cycler
objet lui-même n'est accessible (publiquement ou en privé) nulle part. Au lieu de cela, seule l'itertools.cycle
instance créée à partir de l'cycler
objet est accessible. Dans tous les cas, il n'y a aucun moyen d'accéder à l'état sous-jacent du cycleur couleur / propriété.Faites correspondre la couleur de l'élément précédemment tracé à la place
Dans votre cas, il semble que vous vouliez faire correspondre la couleur de quelque chose qui vient d'être tracé. Au lieu d'essayer de déterminer quelle sera la couleur / la propriété, définissez la couleur / etc de votre nouvel élément en fonction des propriétés de ce qui est tracé.
Par exemple, dans le cas que vous avez décrit, je ferais quelque chose comme ceci:
import matplotlib.pyplot as plt import numpy as np def custom_plot(x, y, **kwargs): ax = kwargs.pop('ax', plt.gca()) base_line, = ax.plot(x, y, **kwargs) ax.fill_between(x, 0.9*y, 1.1*y, facecolor=base_line.get_color(), alpha=0.5) x = np.linspace(0, 1, 10) custom_plot(x, x) custom_plot(x, 2*x) custom_plot(x, -x, color='yellow', lw=3) plt.show()
Ce n'est pas le seul moyen, mais c'est plus propre que d'essayer d'obtenir la couleur de la ligne tracée à l'avance, dans ce cas.
la source
line, = ax.plot(x, y)
, puis utilisezline.get_color()
pour obtenir la couleur de la ligne précédemment tracée.ax._get_lines.color_cycle
n'existe plus en 1.5?ax._get_lines.prop_cycler
vous pouvez avoir une construction quelque chose commeif 'color' in ax._get_lines._prop_keys:
suivi denext(ax._get_lines.prop_cycler)['color']
pour faire l'équivalent de ce qui est suggérécolor_cycle
dans la réponse, je crois. Je ne sais pas si vous pouvez obtenir une itération des couleurs uniquement, j'aurais besoin d'explorer davantage.Voici un moyen qui fonctionne dans la version 1.5 qui, espérons-le, sera à l'épreuve du temps car il ne repose pas sur des méthodes précédées de traits de soulignement:
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
Cela vous donnera une liste des couleurs définies dans l'ordre pour le style actuel.
la source
Remarque: dans les dernières versions de matplotlib (> = 1.5)
_get_lines
a changé. Vous devez maintenant l'utilisernext(ax._get_lines.prop_cycler)['color']
en Python 2 ou 3 (ouax._get_lines.prop_cycler.next()['color']
en Python 2 ) pour obtenir la couleur suivante du cycle de couleurs.Dans la mesure du possible, utilisez l'approche plus directe indiquée dans la partie inférieure de la réponse de @ joe-kington. Comme il
_get_lines
ne fait pas face à l'API, il pourrait changer à nouveau d'une manière non rétrocompatible à l'avenir.la source
Bien sûr, cela le fera.
#rainbow import matplotlib.pyplot as plt import numpy as np x = np.linspace(0,2*np.pi) ax= plt.subplot(1,1,1) ax.plot(np.sin(x)) ax.plot(np.cos(x)) rainbow = ax._get_lines.color_cycle print rainbow for i, color in enumerate(rainbow): if i<10: print color,
Donne:
<itertools.cycle object at 0x034CB288> r c m y k b g r c m
Voici la fonction itertools que matplotlib utilise itertools.cycle
Edit: Merci pour le commentaire, il semble qu'il n'est pas possible de copier un itérateur. Une idée serait de vider un cycle complet et de garder une trace de la valeur que vous utilisez, laissez-moi revenir là-dessus.
Edit2: Très bien, cela vous donnera la couleur suivante et créera un nouvel itérateur qui se comporte comme si le prochain n'était pas appelé. Cela ne préserve pas l'ordre de coloration, juste la valeur de couleur suivante, je vous laisse cela.
Cela donne la sortie suivante, notez que la pente du tracé correspond à l'indice, par exemple, le premier g est le graphe le plus bas et ainsi de suite.
#rainbow import matplotlib.pyplot as plt import numpy as np import collections import itertools x = np.linspace(0,2*np.pi) ax= plt.subplot(1,1,1) def create_rainbow(): rainbow = [ax._get_lines.color_cycle.next()] while True: nextval = ax._get_lines.color_cycle.next() if nextval not in rainbow: rainbow.append(nextval) else: return rainbow def next_color(axis_handle=ax): rainbow = create_rainbow() double_rainbow = collections.deque(rainbow) nextval = ax._get_lines.color_cycle.next() double_rainbow.rotate(-1) return nextval, itertools.cycle(double_rainbow) for i in range(1,10): nextval, ax._get_lines.color_cycle = next_color(ax) print "Next color is: ", nextval ax.plot(i*(x)) plt.savefig("SO_rotate_color.png") plt.show()
Console
Next color is: g Next color is: c Next color is: y Next color is: b Next color is: r Next color is: m Next color is: k Next color is: g Next color is: c
la source
Je veux juste ajouter ce que @Andi a dit ci-dessus. Comme il
color_cycle
est obsolète dans matplotlib 1.5, vous devez utiliserprop_cycler
, cependant, la solution d'Andi (ax._get_lines.prop_cycler.next()['color']
) a renvoyé cette erreur pour moi:Le code qui a fonctionné pour moi était
next(ax._get_lines.prop_cycler)
:, qui n'est pas loin de la réponse originale de @ joe-kington.Personnellement, j'ai rencontré ce problème lors de la création d'un axe twinx (), qui réinitialise le cycleur de couleur. J'avais besoin d'un moyen de faire le cycle des couleurs correctement parce que j'utilisais
style.use('ggplot')
. Il pourrait y avoir un moyen plus facile / meilleur de le faire, alors n'hésitez pas à me corriger.la source
next(ax._get_lines.prop_cycler)
s'agit d'une alternative possible.next(ax._get_lines.prop_cycler)
change réellement l'état du cycleur de couleur?prop_cycler
. Si vous lisez la réponse acceptée à cette question, vous verrez qu'il n'y a aucun moyen d'accéder à l'état deprop_cycler
sans changer son état car c'est un itérable.Depuis l'utilisation de matplotlib,
itertools.cycle
nous pouvons en fait parcourir tout le cycle de couleur, puis restaurer l'itérateur à son état précédent:def list_from_cycle(cycle): first = next(cycle) result = [first] for current in cycle: if current == first: break result.append(current) # Reset iterator state: for current in cycle: if current == result[-1]: break return result
Cela devrait renvoyer la liste sans changer l'état de l'itérateur.
Utilisez-le avec matplotlib> = 1.5:
>>> list_from_cycle(ax._get_lines.prop_cycler) [{'color': 'r'}, {'color': 'g'}, {'color': 'b'}]
ou avec matplotlib <1,5:
>>> list_from_cycle(ax._get_lines.color_cycle) ['r', 'g', 'b']
la source
Le moyen le plus simple que je pourrais trouver sans faire toute la boucle à travers le cycleur est
ax1.lines[-1].get_color()
.la source
Dans matplotlib version 2.2.3, il existe une
get_next_color()
méthode sur la_get_lines
propriété:import from matplotlib import pyplot as plt fig, ax = plt.subplots() next_color = ax._get_lines.get_next_color()
get_next_color()
renvoie une chaîne de couleurs html et fait avancer l'itérateur du cycle de couleurs.la source
Comment accéder au cycle couleur (et style complet)?
L'état actuel est stocké dans
ax._get_lines.prop_cycler
. Il n'y a pas de méthode intégrée pour exposer la "liste de base" pour un génériqueitertools.cycle
, et en particulier pourax._get_lines.prop_cycler
(voir ci-dessous).J'ai posté ici quelques fonctions pour obtenir des informations sur un fichier
itertools.cycle
. On pourrait alors utiliserstyle_cycle = ax._get_lines.prop_cycler curr_style = get_cycle_state(style_cycle) # <-- my (non-builtin) function curr_color = curr_style['color']
pour obtenir la couleur actuelle sans changer l'état du cycle .
TL; DR
Où est stocké le cycle de couleur (et le style complet)?
Le cycle de style est stocké à deux endroits différents, un pour la valeur par défaut et un pour les axes courants (en supposant que
import matplotlib.pyplot as plt
etax
est un gestionnaire d'axe):default_prop_cycler = plt.rcParams['axes.prop_cycle'] current_prop_cycle = ax._get_lines.prop_cycler
Notez que ceux-ci ont des classes différentes. La valeur par défaut est un "réglage du cycle de base" et il ne connaît aucun état actuel pour aucun axe, tandis que le courant connaît le cycle à suivre et son état actuel:
print('type(default_prop_cycler) =', type(default_prop_cycler)) print('type(current_prop_cycle) =', type(current_prop_cycle)) []: type(default_prop_cycler) = <class 'cycler.Cycler'> []: type(current_prop_cycle) = <class 'itertools.cycle'>
Le cycle par défaut peut avoir plusieurs clés (propriétés) à parcourir, et on ne peut obtenir que les couleurs:
print('default_prop_cycler.keys =', default_prop_cycler.keys) default_prop_cycler2 = plt.rcParams['axes.prop_cycle'].by_key() print(default_prop_cycler2) print('colors =', default_prop_cycler2['color']) []: default_prop_cycler.keys = {'color', 'linestyle'} []: {'color': ['r', 'g', 'b', 'y'], 'linestyle': ['-', '--', ':', '-.']} []: colors = ['r', 'g', 'b', 'y']
On pourrait même changer le
cycler
à utiliser pour une donnéeaxes
, après avoir défini celacustom_prop_cycler
, avecMais il n'y a pas de méthode intégrée pour exposer la "liste de base" pour un générique
itertools.cycle
, et en particulier pourax._get_lines.prop_cycler
.la source