web-dev-qa-db-de.com

Matplotlib-Plotlinien mit Farben durch Colormap

Ich zeichne mehrere Linien in einer einzigen Grafik und möchte, dass sie durch das Spektrum einer Farbkarte laufen, nicht nur durch die gleichen 6 oder 7 Farben. Der Code ist dem ähnlich:

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

Sowohl mit Colormap "Jet" als auch mit einer anderen, die ich von Seaborn importiert habe, bekomme ich die gleichen 7 Farben in derselben Reihenfolge wiederholt. Ich möchte bis zu ~ 60 verschiedene Linien mit unterschiedlichen Farben zeichnen können.

7
Scott

Die Matplotlib-Colormaps akzeptieren ein Argument (0..1, Skalar oder Array), mit dem Sie Farben aus einer Colormap erhalten. Zum Beispiel:

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

Gibt Ihnen ein Array mit (zwei) RGBA-Farben:

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

Sie können das verwenden, um N verschiedene Farben zu erstellen:

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

Barts Lösung ist nett und einfach, hat aber zwei Mängel.

  1. plt.colorbar() funktioniert nicht auf nette Art und Weise, da die Liniendiagramme nicht zugeordnet werden können (verglichen mit einem Bild).

  2. Bei einer großen Anzahl von Zeilen kann es aufgrund der for-Schleife langsam sein (obwohl dies für die meisten Anwendungen vielleicht kein Problem ist?)

Diese Probleme können mit LineCollection behoben werden. Dies ist meiner Meinung nach jedoch nicht zu benutzerfreundlich. Es gibt einen offenen Vorschlag auf GitHub , um eine mehrfarbige Liniendiagrammfunktion hinzuzufügen, ähnlich der Funktion plt.scatter(...).

Hier ist ein Arbeitsbeispiel, das ich zusammen hacken konnte

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

Hier ist ein sehr einfaches Beispiel:

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

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

Produziert:

 Example 1

Und etwas anspruchsvoller:

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')

Produziert:

 enter image description here

Hoffe das hilft!

6
Alex Williams

Eine Alternative zu Barts Antwort, in der Sie nicht die Farbe in jedem Aufruf von plt.plot angeben, besteht darin, mit set_prop_cycle einen neuen Farbzyklus zu definieren. Sein Beispiel kann in den folgenden Code übersetzt werden (ich habe auch den Import von matplotlib in den empfohlenen Stil geändert):

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

Wenn Sie kontinuierliche Farbpaletten wie brg, hsv, jet oder die Standardpalette verwenden, können Sie dies wie folgt tun:

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

Jetzt können Sie diesen Farbwert an eine beliebige API übergeben, die Sie wie folgt wünschen:

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