web-dev-qa-db-fra.com

Matplotlib Lignes de tracé avec des couleurs à travers la palette de couleurs

Je trace plusieurs lignes sur un même tracé et je veux qu'elles couvrent tout le spectre d'une palette de couleurs, pas uniquement les mêmes 6 ou 7 couleurs. Le code s'apparente à ceci:

for i in range(20):
     for k in range(100):
          y[k] = i*x[i]
     plt.plot(x,y)
plt.show()

Avec la palette de couleurs "jet" et une autre importée de Seaborn, les 7 mêmes couleurs sont répétées dans le même ordre. J'aimerais pouvoir tracer jusqu'à ~ 60 lignes différentes, toutes avec des couleurs différentes.

7
Scott

Les tables de couleurs Matplotlib acceptent un argument (0..1, scalaire ou un tableau) que vous utilisez pour obtenir les couleurs d'une carte de couleurs. Par exemple:

col = pl.cm.jet([0.25,0.75])    

Vous donne un tableau avec (deux) couleurs RGBA:

tableau ([[0., 0.50392157, 1., 1.], [1., 0.58169935, 0., 1.]])

Vous pouvez l'utiliser pour créer N différentes couleurs:

import numpy as np
import matplotlib.pylab as pl

x = np.linspace(0, 2*np.pi, 64)
y = np.cos(x) 

pl.figure()
pl.plot(x,y)

n = 20
colors = pl.cm.jet(np.linspace(0,1,n))

for i in range(n):
    pl.plot(x, i*y, color=colors[i])

 enter image description here

18
Bart

La solution de Bart est simple et agréable, mais présente deux inconvénients.

  1. plt.colorbar() ne fonctionnera pas de façon agréable, car les tracés linéaires ne sont pas mappables (par exemple, une image)

  2. Cela peut être lent pour un grand nombre de lignes en raison de la boucle for (bien que cela ne pose peut-être pas un problème pour la plupart des applications?)

Ces problèmes peuvent être résolus en utilisant LineCollection . Cependant, ce n'est pas trop convivial selon mon (humble) opinion. Il existe une suggestion ouverte sur GitHub pour l’ajout d’une fonction de tracé de tracé multicolore, similaire à la fonction plt.scatter(...).

Voici un exemple de travail que j'ai pu pirater

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection

def multiline(xs, ys, c, ax=None, **kwargs):
    """Plot lines with different colorings

    Parameters
    ----------
    xs : iterable container of x coordinates
    ys : iterable container of y coordinates
    c : iterable container of numbers mapped to colormap
    ax (optional): Axes to plot on.
    kwargs (optional): passed to LineCollection

    Notes:
        len(xs) == len(ys) == len(c) is the number of line segments
        len(xs[i]) == len(ys[i]) is the number of points for each line (indexed by i)

    Returns
    -------
    lc : LineCollection instance.
    """

    # find axes
    ax = plt.gca() if ax is None else ax

    # create LineCollection
    segments = [np.column_stack([x, y]) for x, y in Zip(xs, ys)]
    lc = LineCollection(segments, **kwargs)

    # set coloring of line segments
    #    Note: I get an error if I pass c as a list here... not sure why.
    lc.set_array(np.asarray(c))

    # add lines to axes and rescale 
    #    Note: adding a collection doesn't autoscalee xlim/ylim
    ax.add_collection(lc)
    ax.autoscale()
    return lc

Voici un exemple très simple:

xs = [[0, 1],
      [0, 1, 2]]
ys = [[0, 0],
      [1, 2, 1]]
c = [0, 1]

lc = multiline(xs, ys, c, cmap='bwr', lw=2)

Produit:

 Example 1

Et quelque chose d'un peu plus sophistiqué:

n_lines = 30
x = np.arange(100)

yint = np.arange(0, n_lines*10, 10)
ys = np.array([x + b for b in yint])
xs = np.array([x for i in range(n_lines)]) # could also use np.tile

colors = np.arange(n_lines)

fig, ax = plt.subplots()
lc = multiline(xs, ys, yint, cmap='bwr', lw=2)

axcb = fig.colorbar(lc)
axcb.set_label('Y-intercept')
ax.set_title('Line Collection with mapped colors')

Produit:

 enter image description here

J'espère que cela t'aides!

6
Alex Williams

Une alternative à la réponse de Bart, dans laquelle vous ne spécifiez pas la couleur dans chaque appel à plt.plot, consiste à définir un nouveau cycle de couleur avec set_prop_cycle. Son exemple peut être traduit dans le code suivant (j'ai également modifié l'importation de matplotlib dans le style recommandé):

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 64)
y = np.cos(x) 

n = 20
ax = plt.axes()
ax.set_prop_cycle('color',[plt.cm.jet(i) for i in np.linspace(0, 1, n)])

for i in range(n):
    plt.plot(x, i*y)
3
Ramon Crehuet

Si vous utilisez des palettes de couleurs continues comme brg, hsv, jet ou celle par défaut, vous pouvez procéder comme suit:

color = plt.cm.hsv(r) # r is 0 to 1 inclusive

Maintenant, vous pouvez transmettre cette valeur de couleur à n’importe quelle API de ce type:

line = matplotlib.lines.Line2D(xdata, ydata, color=color)
2
Shital Shah