Membalikkan colormap di matplotlib

252

Saya ingin tahu bagaimana cara membalik urutan warna colormap yang diberikan untuk menggunakannya dengan plot_surface.

Mermoz
sumber

Jawaban:

463

Colormaps standar juga semuanya memiliki versi terbalik. Mereka memiliki nama yang sama dengan _rditempel sampai akhir. ( Dokumentasi di sini. )

ptomato
sumber
Ini tidak berfungsi dengan "amfhot": "ValueError: Colormap amfhot_r tidak dikenali". Saya kira "hot_r" harus cukup.
shockburner
Demikian pula, "ValueError: Colormap red_r tidak dikenali."
Alex Willison
18

Dalam matplotlib peta warna bukan daftar, tetapi berisi daftar warnanya sebagai colormap.colors. Dan modul matplotlib.colorsmenyediakan fungsi ListedColormap()untuk menghasilkan peta warna dari daftar. Jadi, Anda dapat membalikkan peta warna apa pun dengan melakukan

colormap_r = ListedColormap(colormap.colors[::-1])
Gilles
sumber
7
+1. Namun, ini tidak akan secara umum membalikkan colormap apa pun. Hanya ListedColormaps (yaitu diskrit, alih-alih diinterpolasi) yang memiliki colorsatribut. Membalik LinearSegmentedColormapssedikit lebih rumit. (Anda harus membalikkan setiap item dalam _segmentdatadikt.)
Joe Kington
3
Mengenai pembalikan LinearSegmentedColormaps, saya hanya melakukan ini untuk beberapa colourmaps. Inilah Notebook IPython tentang hal itu.
kwinkunks
@kwinkunks saya pikir fungsi di notebook Anda tidak benar, lihat jawaban di bawah ini
Mattijn
14

Solusinya cukup mudah. Misalkan Anda ingin menggunakan skema colormap "musim gugur". Versi standar:

cmap = matplotlib.cm.autumn

Untuk membalikkan spektrum warna colormap, gunakan fungsi get_cmap () dan tambahkan '_r' ke judul colormap seperti ini:

cmap_reversed = matplotlib.cm.get_cmap('autumn_r')
Jm M
sumber
dapatkah Anda memberikan tautan dokumentasi dari mana Anda mendapatkan .autumn?
Xitcod13
Ini mungkin pecah nanti ... matplotlib.org/3.1.1/gallery/color/colormap_reference.html , tapi saya yakin siapa pun yang tertarik akan dapat menemukan ini dengan pencarian.
Jlanger
13

Karena LinearSegmentedColormapsdidasarkan pada kamus merah, hijau dan biru, Anda perlu membalik setiap item:

import matplotlib.pyplot as plt
import matplotlib as mpl
def reverse_colourmap(cmap, name = 'my_cmap_r'):
    """
    In: 
    cmap, name 
    Out:
    my_cmap_r

    Explanation:
    t[0] goes from 0 to 1
    row i:   x  y0  y1 -> t[0] t[1] t[2]
                   /
                  /
    row i+1: x  y0  y1 -> t[n] t[1] t[2]

    so the inverse should do the same:
    row i+1: x  y1  y0 -> 1-t[0] t[2] t[1]
                   /
                  /
    row i:   x  y1  y0 -> 1-t[n] t[2] t[1]
    """        
    reverse = []
    k = []   

    for key in cmap._segmentdata:    
        k.append(key)
        channel = cmap._segmentdata[key]
        data = []

        for t in channel:                    
            data.append((1-t[0],t[2],t[1]))            
        reverse.append(sorted(data))    

    LinearL = dict(zip(k,reverse))
    my_cmap_r = mpl.colors.LinearSegmentedColormap(name, LinearL) 
    return my_cmap_r

Lihat itu berfungsi:

my_cmap        
<matplotlib.colors.LinearSegmentedColormap at 0xd5a0518>

my_cmap_r = reverse_colourmap(my_cmap)

fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = my_cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = my_cmap_r, norm=norm, orientation='horizontal')

masukkan deskripsi gambar di sini

EDIT


Saya tidak mendapatkan komentar dari user3445587. Ini berfungsi dengan baik pada rainbow colormap:

cmap = mpl.cm.jet
cmap_r = reverse_colourmap(cmap)

fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = cmap_r, norm=norm, orientation='horizontal')

masukkan deskripsi gambar di sini

Tapi itu terutama berfungsi baik untuk colormaps yang dinyatakan kustom, karena tidak ada default _runtuk colormaps dinyatakan kustom. Contoh berikut diambil dari http://matplotlib.org/examples/pylab_examples/custom_cmap.html :

cdict1 = {'red':   ((0.0, 0.0, 0.0),
                   (0.5, 0.0, 0.1),
                   (1.0, 1.0, 1.0)),

         'green': ((0.0, 0.0, 0.0),
                   (1.0, 0.0, 0.0)),

         'blue':  ((0.0, 0.0, 1.0),
                   (0.5, 0.1, 0.0),
                   (1.0, 0.0, 0.0))
         }

blue_red1 = mpl.colors.LinearSegmentedColormap('BlueRed1', cdict1)
blue_red1_r = reverse_colourmap(blue_red1)

fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])

norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = blue_red1, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = blue_red1_r, norm=norm, orientation='horizontal')

masukkan deskripsi gambar di sini

Mattijn
sumber
Contoh ini tidak lengkap dalam arti bahwa data segmen tidak berada dalam daftar sehingga tidak perlu dibalik (misalnya colormap pelangi standar). Saya pikir pada prinsipnya semua LinearSegmentedColormaps harus pada prinsipnya dapat dibalik menggunakan fungsi lambda seperti pada rainbow colormap?
luar negeri
@ user3445587 Saya menambahkan beberapa contoh lagi, tapi saya pikir itu berfungsi dengan baik pada colormap pelangi standar
Mattijn
Karena sudah terlalu lama, saya menambahkan jawaban baru, yang seharusnya bisa digunakan untuk semua jenis LinearSegmentData. Masalahnya adalah bahwa untuk pelangi, _segmentdata diimplementasikan secara berbeda. Jadi kode Anda - setidaknya di komputer saya - tidak berfungsi dengan pelangi colormap.
luar negeri
12

Pada Matplotlib 2.0, ada reversed()metode untuk ListedColormapdan LinearSegmentedColorMapobjek, jadi Anda bisa melakukannya

cmap_reversed = cmap.reversed()

Ini dokumentasinya.

David Stansby
sumber
1

Ada dua jenis LinearSegmentedColormaps. Dalam beberapa, _segmentdata diberikan secara eksplisit, misalnya, untuk jet:

>>> cm.jet._segmentdata
{'blue': ((0.0, 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65, 0, 0), (1, 0, 0)), 'red': ((0.0, 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89, 1, 1), (1, 0.5, 0.5)), 'green': ((0.0, 0, 0), (0.125, 0, 0), (0.375, 1, 1), (0.64, 1, 1), (0.91, 0, 0), (1, 0, 0))}

Untuk pelangi, _segmentdata diberikan sebagai berikut:

>>> cm.rainbow._segmentdata
{'blue': <function <lambda> at 0x7fac32ac2b70>, 'red': <function <lambda> at 0x7fac32ac7840>, 'green': <function <lambda> at 0x7fac32ac2d08>}

Kita dapat menemukan fungsi-fungsi di sumber matplotlib, di mana mereka diberikan sebagai

_rainbow_data = {
        'red': gfunc[33],   # 33: lambda x: np.abs(2 * x - 0.5),
        'green': gfunc[13], # 13: lambda x: np.sin(x * np.pi),
        'blue': gfunc[10],  # 10: lambda x: np.cos(x * np.pi / 2)
}

Semua yang Anda inginkan sudah dilakukan di matplotlib, panggil saja cm.revcmap, yang membalikkan kedua jenis segmentdata, jadi

cm.revcmap(cm.rainbow._segmentdata)

harus melakukan pekerjaan - Anda cukup membuat LinearSegmentData baru dari itu. Di revcmap, pembalikan fungsi berdasarkan SegmentData dilakukan dengan

def _reverser(f):
    def freversed(x):
        return f(1 - x)
    return freversed

sementara daftar lainnya dibalik seperti biasa

valnew = [(1.0 - x, y1, y0) for x, y0, y1 in reversed(val)] 

Jadi sebenarnya semua yang Anda inginkan, adalah

def reverse_colourmap(cmap, name = 'my_cmap_r'):
     return mpl.colors.LinearSegmentedColormap(name, cm.revcmap(cmap._segmentdata)) 
luar negeri
sumber
1

Tidak ada cara bawaan untuk membalikkan colormaps yang sewenang-wenang, tetapi satu solusi sederhana adalah dengan benar-benar tidak memodifikasi colorbar tetapi untuk membuat objek Normalisasi pembalik:

from matplotlib.colors import Normalize

class InvertedNormalize(Normalize):
    def __call__(self, *args, **kwargs):
        return 1 - super(InvertedNormalize, self).__call__(*args, **kwargs)

Anda kemudian dapat menggunakan ini dengan plot_surfacedan fungsi merencanakan Matplotlib lainnya dengan melakukan mis

inverted_norm = InvertedNormalize(vmin=10, vmax=100)
ax.plot_surface(..., cmap=<your colormap>, norm=inverted_norm)

Ini akan bekerja dengan colormap Matplotlib.

astrofrog
sumber
Ada sekarang! matplotlib.org/api/_as_gen/…
David Stansby