Saya mencoba membuat colorbar diskrit untuk sebar di matplotlib
Saya memiliki data x, y dan untuk setiap titik nilai tag integer yang ingin saya wakili dengan warna yang unik, misalnya
plt.scatter(x, y, c=tag)
biasanya tag akan berupa bilangan bulat mulai dari 0-20, tetapi kisaran persisnya dapat berubah
sejauh ini saya baru saja menggunakan pengaturan default, mis
plt.colorbar()
yang memberikan rentang warna yang berkelanjutan. Idealnya saya ingin satu set n warna diskrit (n = 20 dalam contoh ini). Lebih baik lagi untuk mendapatkan nilai tag 0 untuk menghasilkan warna abu-abu dan 1-20 menjadi berwarna.
Saya telah menemukan beberapa skrip 'buku masak' tetapi sangat rumit dan saya tidak dapat berpikir itu adalah cara yang tepat untuk menyelesaikan masalah yang tampaknya sederhana
python
matplotlib
bph
sumber
sumber
Jawaban:
Anda dapat membuat bilah warna diskrit kustom cukup mudah dengan menggunakan BoundaryNorm sebagai normalizer untuk pencar Anda. Bit yang unik (dalam metode saya) membuat 0 muncul sebagai abu-abu.
Untuk gambar saya sering menggunakan cmap.set_bad () dan mengubah data saya menjadi array bertopeng numpy. Itu akan jauh lebih mudah untuk membuat 0 abu-abu, tapi saya tidak bisa membuatnya bekerja dengan pencar atau cmap kustom.
Sebagai alternatif, Anda dapat membuat cmap Anda sendiri dari awal, atau membacakan cmap yang sudah ada dan mengganti hanya beberapa entri tertentu.
import numpy as np import matplotlib as mpl import matplotlib.pylab as plt fig, ax = plt.subplots(1, 1, figsize=(6, 6)) # setup the plot x = np.random.rand(20) # define the data y = np.random.rand(20) # define the data tag = np.random.randint(0, 20, 20) tag[10:12] = 0 # make sure there are some 0 values to show up as grey cmap = plt.cm.jet # define the colormap # extract all colors from the .jet map cmaplist = [cmap(i) for i in range(cmap.N)] # force the first color entry to be grey cmaplist[0] = (.5, .5, .5, 1.0) # create the new map cmap = mpl.colors.LinearSegmentedColormap.from_list( 'Custom cmap', cmaplist, cmap.N) # define the bins and normalize bounds = np.linspace(0, 20, 21) norm = mpl.colors.BoundaryNorm(bounds, cmap.N) # make the scatter scat = ax.scatter(x, y, c=tag, s=np.random.randint(100, 500, 20), cmap=cmap, norm=norm) # create a second axes for the colorbar ax2 = fig.add_axes([0.95, 0.1, 0.03, 0.8]) cb = plt.colorbar.ColorbarBase(ax2, cmap=cmap, norm=norm, spacing='proportional', ticks=bounds, boundaries=bounds, format='%1i') ax.set_title('Well defined discrete colors') ax2.set_ylabel('Very custom cbar [-]', size=12)
Saya pribadi berpikir bahwa dengan 20 warna berbeda agak sulit untuk membaca nilai spesifiknya, tetapi itu terserah Anda tentu saja.
sumber
plt.colorbar.ColorbarBase
melempar Error. Gunakanmpl.colorbar.ColorbarBase
N-1
dalamcmap = mpl.colors.LinearSegmentedColormap.from_list('Custom cmap', cmaplist, cmap.N-1)
. Jika tidak, warna tidak didistribusikan secara merata di dalam tempat sampah dan Anda memiliki masalah penghalang pagar.q=np.arange(0.0, 1.01, 0.1) cmap = mpl.cm.get_cmap('jet') cmaplist = [cmap(x) for x in q] cmap = mpl.colors.LinearSegmentedColormap.from_list('Custom cmap', cmaplist, len(q)-1) norm = mpl.colors.BoundaryNorm(q, cmap.N)
N-1
, Anda mungkin benar tetapi saya tidak dapat meniru dengan contoh saya. Anda mungkin menghindariLinearSegmentedColormap
(danN
argumennya) dengan menggunakan fileListedColormap
. Dokumen telah meningkat pesat sejak '13, lihat contoh: matplotlib.org/3.1.1/tutorials/colors/…Anda bisa mengikuti contoh ini :
#!/usr/bin/env python """ Use a pcolor or imshow with a custom colormap to make a contour plot. Since this example was initially written, a proper contour routine was added to matplotlib - see contour_demo.py and http://matplotlib.sf.net/matplotlib.pylab.html#-contour. """ from pylab import * delta = 0.01 x = arange(-3.0, 3.0, delta) y = arange(-3.0, 3.0, delta) X,Y = meshgrid(x, y) Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1) Z = Z2 - Z1 # difference of Gaussians cmap = cm.get_cmap('PiYG', 11) # 11 discrete colors im = imshow(Z, cmap=cmap, interpolation='bilinear', vmax=abs(Z).max(), vmin=-abs(Z).max()) axis('off') colorbar() show()
yang menghasilkan gambar berikut:
sumber
Jawaban di atas bagus, kecuali mereka tidak memiliki penempatan centang yang tepat pada bilah warna. Saya suka memiliki tanda centang di tengah warna sehingga angka -> pemetaan warna lebih jelas. Anda dapat mengatasi masalah ini dengan mengubah batas panggilan matshow:
import matplotlib.pyplot as plt import numpy as np def discrete_matshow(data): #get discrete colormap cmap = plt.get_cmap('RdBu', np.max(data)-np.min(data)+1) # set limits .5 outside true range mat = plt.matshow(data,cmap=cmap,vmin = np.min(data)-.5, vmax = np.max(data)+.5) #tell the colorbar to tick at integers cax = plt.colorbar(mat, ticks=np.arange(np.min(data),np.max(data)+1)) #generate data a=np.random.randint(1, 9, size=(10, 10)) discrete_matshow(a)
sumber
set_ticklabels(...)
sebaiknya hanya digunakan untuk mengontrol format label (misalnya angka desimal, dll.). Jika datanya benar-benar terpisah, Anda mungkin tidak melihat adanya masalah. Jika ada gangguan dalam sistem (misalnya 2 -> 1.9), pelabelan yang tidak konsisten ini akan menghasilkan bilah warna yang salah dan menyesatkan.Untuk menetapkan nilai di atas atau di bawah kisaran peta warna, Anda akan ingin menggunakan
set_over
danset_under
metode peta warna. Jika Anda ingin menandai nilai tertentu, tutupi (mis. Buat array bertopeng), dan gunakanset_bad
metode. (Lihat dokumentasi untuk base colormap class: http://matplotlib.org/api/colors_api.html#matplotlib.colors.Colormap )Sepertinya Anda menginginkan sesuatu seperti ini:
import matplotlib.pyplot as plt import numpy as np # Generate some data x, y, z = np.random.random((3, 30)) z = z * 20 + 0.1 # Set some values in z to 0... z[:5] = 0 cmap = plt.get_cmap('jet', 20) cmap.set_under('gray') fig, ax = plt.subplots() cax = ax.scatter(x, y, c=z, s=100, cmap=cmap, vmin=0.1, vmax=z.max()) fig.colorbar(cax, extend='min') plt.show()
sumber
Topik ini sudah dibahas dengan baik tetapi saya ingin menambahkan sesuatu yang lebih spesifik: Saya ingin memastikan bahwa nilai tertentu akan dipetakan ke warna itu (bukan ke warna apa pun).
Ini tidak rumit tetapi karena saya butuh waktu, ini mungkin membantu orang lain agar tidak kehilangan waktu sebanyak yang saya lakukan :)
import matplotlib from matplotlib.colors import ListedColormap # Let's design a dummy land use field A = np.reshape([7,2,13,7,2,2], (2,3)) vals = np.unique(A) # Let's also design our color mapping: 1s should be plotted in blue, 2s in red, etc... col_dict={1:"blue", 2:"red", 13:"orange", 7:"green"} # We create a colormar from our list of colors cm = ListedColormap([col_dict[x] for x in col_dict.keys()]) # Let's also define the description of each category : 1 (blue) is Sea; 2 (red) is burnt, etc... Order should be respected here ! Or using another dict maybe could help. labels = np.array(["Sea","City","Sand","Forest"]) len_lab = len(labels) # prepare normalizer ## Prepare bins for the normalizer norm_bins = np.sort([*col_dict.keys()]) + 0.5 norm_bins = np.insert(norm_bins, 0, np.min(norm_bins) - 1.0) print(norm_bins) ## Make normalizer and formatter norm = matplotlib.colors.BoundaryNorm(norm_bins, len_lab, clip=True) fmt = matplotlib.ticker.FuncFormatter(lambda x, pos: labels[norm(x)]) # Plot our figure fig,ax = plt.subplots() im = ax.imshow(A, cmap=cm, norm=norm) diff = norm_bins[1:] - norm_bins[:-1] tickz = norm_bins[:-1] + diff / 2 cb = fig.colorbar(im, format=fmt, ticks=tickz) fig.savefig("example_landuse.png") plt.show()
sumber
pos
saya tidak sepenuhnya yakin mengapa itu ada di sini tetapi diminta oleh FuncFormatter () ... Mungkin orang lain bisa mencerahkan kami tentang itu!Saya telah menyelidiki ide-ide ini dan inilah nilai lima sen saya. Ini menghindari panggilan
BoundaryNorm
serta menentukannorm
sebagai argumen untukscatter
dancolorbar
. Namun saya tidak menemukan cara untuk menghilangkan panggilan yang bertele-tele kematplotlib.colors.LinearSegmentedColormap.from_list
.Beberapa latar belakang adalah bahwa matplotlib menyediakan apa yang disebut peta warna kualitatif, yang dimaksudkan untuk digunakan dengan data diskrit.
Set1
misalnya memiliki 9 warna yang mudah dibedakan, dantab20
dapat digunakan untuk 20 warna. Dengan peta ini, wajar saja jika menggunakan n warna pertamanya untuk mewarnai plot sebar dengan n kategori, seperti contoh berikut. Contoh ini juga menghasilkan bilah warna dengan n warna berlainan diberi label yang sesuai.import matplotlib, numpy as np, matplotlib.pyplot as plt n = 5 from_list = matplotlib.colors.LinearSegmentedColormap.from_list cm = from_list(None, plt.cm.Set1(range(0,n)), n) x = np.arange(99) y = x % 11 z = x % n plt.scatter(x, y, c=z, cmap=cm) plt.clim(-0.5, n-0.5) cb = plt.colorbar(ticks=range(0,n), label='Group') cb.ax.tick_params(length=0)
yang menghasilkan gambar di bawah ini. Dalam
n
panggilan untukSet1
menentukann
warna pertama dari peta warna itu, dan yang terakhirn
dalam panggilan untukfrom_list
menentukan untuk membuat peta dengann
warna (defaultnya 256). Untuk menetapkancm
sebagai peta warna defaultplt.set_cmap
, saya merasa perlu untuk memberinya nama dan mendaftarkannya, yaitu:cm = from_list('Set15', plt.cm.Set1(range(0,n)), n) plt.cm.register_cmap(None, cm) plt.set_cmap(cm) ... plt.scatter(x, y, c=z)
sumber
Saya pikir Anda ingin melihat colors.ListedColormap untuk menghasilkan peta warna Anda, atau jika Anda hanya memerlukan peta warna statis, saya telah mengerjakan aplikasi yang mungkin membantu.
sumber