Atur ukuran colorbar Matplotlib agar sesuai dengan grafik

161

Saya tidak bisa mendapatkan colorbar pada grafik imshow seperti ini sama tingginya dengan grafik, singkatnya menggunakan Photoshop. Bagaimana cara mendapatkan ketinggian yang cocok?Contoh ketidakcocokan ukuran colorbar

Elliot
sumber
Sudahkah Anda mencoba saran dari stackoverflow.com/questions/16702479/…
lmjohns3
@ imjohns3 Tidak ada dalam posting itu yang tampaknya melakukan apa pun pada bilah warna. Ukurannya tetap sama, apa pun yang saya atur. Jika saya mengatur pecahan dan menyusut, ukuran grafik akan berubah sementara bilah warna tetap sama, sampai kita kembali ke apa yang sudah saya miliki, maka mereka berhenti melakukan apa pun.
Elliot
Lihatlah dokumen - matplotlib.org/api/colorbar_api.html - dan gunakan fractionatau shrinkargumen.
BoltzmannBrain

Jawaban:

194

Anda dapat melakukan ini dengan mudah dengan AxisDivider matplotlib .

Contoh dari halaman tertaut juga berfungsi tanpa menggunakan subplot:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np

plt.figure()
ax = plt.gca()
im = ax.imshow(np.arange(100).reshape((10,10)))

# create an axes on the right side of ax. The width of cax will be 5%
# of ax and the padding between cax and ax will be fixed at 0.05 inch.
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)

plt.colorbar(im, cax=cax)

masukkan deskripsi gambar di sini

bogatron
sumber
1
Saya tidak bekerja di dalam subplot, jadi ini tidak berlaku.
Elliot
Setelah banyak mengutak-atik, mulai bekerja. Memiliki banyak kesulitan berinteraksi dengan subplot_adjust, Anda harus mendapatkan panggilan di tempat yang tepat relatif satu sama lain.
Elliot
11
Ini sedikit mengubah ukuran grafik. Saya memiliki 4 di kotak 2x2, tetapi hanya ingin dua di sebelah kanan memiliki bilah (skala berlaku dengan baris). Namun ini membuat ukuran mereka tidak sama. Saya mencoba tidak memiliki panggilan colorbar (dengan panggilan pembagi), tetapi tentu saja ini meninggalkan kotak putih kosong dan angka di samping. Bagaimana saya membuat mereka memiliki ukuran yang konsisten tanpa menempatkan bar pada mereka semua?
Elliot
@ bogatron Sayangnya ini tidak bekerja dengan sumbu yang diproyeksikan
Bogdan
Jika Anda ingin menambahkan judul menggunakan plt.title, itu akan ditampilkan ditukar ke kanan. Apakah ada cara untuk mengatasi ini?
user2820579
225

Kombinasi ini (dan nilai yang dekat dengan ini) tampaknya "ajaib" berfungsi bagi saya untuk menjaga colorbar diskalakan ke plot, tidak peduli berapa ukuran layar.

plt.colorbar(im,fraction=0.046, pad=0.04)

Ini juga tidak memerlukan berbagi sumbu yang dapat membuat plot keluar dari kotak.

pembuat skytaker
sumber
4
Ini mungkin bekerja dalam beberapa kasus, tetapi secara umum tidak. Coba, misalnya, merencanakan sesuatu seperti dalam pertanyaan awal, yang memiliki lebar dua kali tinggi.
Matthias 15
Pilihan fraksi masih berfungsi dalam kasus yang Anda sebutkan, jika diskalakan agar sesuai dengan ketinggian plot. (mpl v1.4.3)
skytaker
6
Ini adalah satu-satunya cara universal untuk melakukannya. Solusi dengan axex_grid1 tidak akan berfungsi untuk sumbu yang diproyeksikan seperti GeoAxes.
Bogdan
OMG ini luar biasa. Terima kasih banyak atas solusinya
2D_
3
Menanggapi komentar @Matthias. Anda dapat memperbaiki kasus di mana gambar terlalu lebar menggunakan trik ini: di im_ratio = data.shape[0]/data.shape[1] plt.colorbar(im,fraction=0.046*im_ratio, pad=0.04)mana datagambar Anda.
eindzl
30

@ bogatron sudah memberikan jawaban yang disarankan oleh docs matplotlib , yang menghasilkan ketinggian yang tepat, tetapi memperkenalkan masalah yang berbeda. Sekarang lebar colorbar (dan juga ruang antara colorbar dan plot) berubah dengan lebar plot. Dengan kata lain, rasio aspek dari colorbar tidak diperbaiki lagi.

Untuk mendapatkan ketinggian yang tepat dan rasio aspek tertentu, Anda harus menggali lebih dalam axes_grid1modul misterius .

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size
import numpy as np

aspect = 20
pad_fraction = 0.5

ax = plt.gca()
im = ax.imshow(np.arange(200).reshape((20, 10)))
divider = make_axes_locatable(ax)
width = axes_size.AxesY(ax, aspect=1./aspect)
pad = axes_size.Fraction(pad_fraction, width)
cax = divider.append_axes("right", size=width, pad=pad)
plt.colorbar(im, cax=cax)

Perhatikan bahwa ini menentukan lebar colorbar dengan ketinggian plot (berbeda dengan lebar gambar, seperti sebelumnya).

Jarak antara colorbar dan plot sekarang dapat ditentukan sebagai sebagian kecil dari lebar colorbar, yang merupakan angka yang jauh lebih bermakna dari pada sebagian kecil dari lebar gambar.

plot gambar dengan colorbar

MEMPERBARUI:

Saya membuat notebook IPython pada topik , di mana saya mengemas kode di atas menjadi fungsi yang dapat digunakan kembali:

import matplotlib.pyplot as plt
from mpl_toolkits import axes_grid1

def add_colorbar(im, aspect=20, pad_fraction=0.5, **kwargs):
    """Add a vertical color bar to an image plot."""
    divider = axes_grid1.make_axes_locatable(im.axes)
    width = axes_grid1.axes_size.AxesY(im.axes, aspect=1./aspect)
    pad = axes_grid1.axes_size.Fraction(pad_fraction, width)
    current_ax = plt.gca()
    cax = divider.append_axes("right", size=width, pad=pad)
    plt.sca(current_ax)
    return im.axes.figure.colorbar(im, cax=cax, **kwargs)

Dapat digunakan seperti ini:

im = plt.imshow(np.arange(200).reshape((20, 10)))
add_colorbar(im)
Matthias
sumber
1
Ini adalah fungsi kecil yang sangat membantu! Satu kata peringatan adalah bahwa itu tidak berfungsi ketika Anda ingin menambahkan beberapa colorbar, karena mereka muncul di atas satu sama lain.
David Hall
22

Saya menghargai semua jawaban di atas. Namun, seperti beberapa jawaban dan komentar mencontohkan, axes_grid1modul tidak bisa GeoAxes alamat, sedangkan menyesuaikan fraction, pad, shrink, dan parameter lain yang serupa dapat belum tentu memberikan perintah yang sangat tepat, yang benar-benar mengganggu saya. Saya percaya bahwa memberikan colorbarsendiri axesmungkin merupakan solusi yang lebih baik untuk mengatasi semua masalah yang telah disebutkan.

Kode

import matplotlib.pyplot as plt
import numpy as np

fig=plt.figure()
ax = plt.axes()
im = ax.imshow(np.arange(100).reshape((10,10)))

# Create an axes for colorbar. The position of the axes is calculated based on the position of ax.
# You can change 0.01 to adjust the distance between the main image and the colorbar.
# You can change 0.02 to adjust the width of the colorbar.
# This practice is universal for both subplots and GeoAxes.

cax = fig.add_axes([ax.get_position().x1+0.01,ax.get_position().y0,0.02,ax.get_position().height])
plt.colorbar(im, cax=cax) # Similar to fig.colorbar(im, cax = cax)

Hasil

masukkan deskripsi gambar di sini

Kemudian, saya menemukan matplotlib.pyplot.colorbardokumentasi resmi juga memberikan axopsi, yaitu sumbu yang ada yang akan memberikan ruang untuk colorbar. Karenanya, ini berguna untuk banyak subplot, lihat berikut.

Kode

fig, ax = plt.subplots(2,1,figsize=(12,8)) # Caution, figsize will also influence positions.
im1 = ax[0].imshow(np.arange(100).reshape((10,10)), vmin = -100, vmax =100)
im2 = ax[1].imshow(np.arange(-100,0).reshape((10,10)), vmin = -100, vmax =100)
fig.colorbar(im1, ax=ax)

Hasil

masukkan deskripsi gambar di sini

Sekali lagi, Anda juga dapat mencapai efek yang sama dengan menentukan cax, cara yang lebih akurat dari sudut pandang saya.

Kode

fig, ax = plt.subplots(2,1,figsize=(12,8))
im1 = ax[0].imshow(np.arange(100).reshape((10,10)), vmin = -100, vmax =100)
im2 = ax[1].imshow(np.arange(-100,0).reshape((10,10)), vmin = -100, vmax =100)
cax = fig.add_axes([ax[1].get_position().x1-0.25,ax[1].get_position().y0,0.02,ax[0].get_position().y1-ax[1].get_position().y0])
fig.colorbar(im1, cax=cax)

Hasil

masukkan deskripsi gambar di sini

Fei Yao
sumber
@ HS-nebula Terima kasih atas komentar Anda dan saya senang Anda menikmatinya. :)
Fei Yao
Jawaban yang sangat menakjubkan. Terima kasih!!
episodeyang
11

Saat Anda membuat colorbarcoba gunakan fraksi dan / atau susutkan parameter.

Dari dokumen:

fraksi 0,15; sebagian kecil dari sumbu asli yang digunakan untuk colorbar

menyusut 1.0; fraksi yang digunakan untuk mengecilkan colorbar

Steve Barnes
sumber
1
Jika saya mengatur menyusut 1.0 dan pecahan menjadi apa pun, itu menyusutkan grafik, sama sekali tidak memengaruhi ukuran bilah warna, sampai mengubah pecahan menyebabkannya persis seperti yang sudah saya miliki, pada titik mana mengubahnya mereka berhenti melakukan apa pun.
Elliot
Di mana tepatnya Anda menentukan mereka, mereka harus menjadi parameter untuk colorbar()fungsi atau metode.
Steve Barnes
Terima kasih. hanya perlu menentukan parameter menyusut dan berfungsi seperti sulap!
CodingNow
11

Semua solusi di atas baik, tapi saya suka @ Steve dan @ bejota yang terbaik karena mereka tidak melibatkan panggilan mewah dan bersifat universal.

Secara universal maksud saya yang bekerja dengan semua jenis sumbu termasuk GeoAxes. Misalnya, Anda telah memproyeksikan sumbu untuk pemetaan:

projection = cartopy.crs.UTM(zone='17N')
ax = plt.axes(projection=projection)
im = ax.imshow(np.arange(200).reshape((20, 10)))

panggilan ke

cax = divider.append_axes("right", size=width, pad=pad)

akan gagal dengan: KeyException: map_projection

Oleh karena itu, satu-satunya cara universal menangani ukuran colorbar dengan semua jenis sumbu adalah:

ax.colorbar(im, fraction=0.046, pad=0.04)

Bekerja dengan pecahan dari 0,035 hingga 0,046 untuk mendapatkan ukuran terbaik Anda. Namun, nilai untuk fraksi dan paddig perlu disesuaikan untuk mendapatkan yang paling cocok untuk plot Anda dan akan berbeda tergantung jika orientasi bar warna berada di posisi vertikal atau horizontal.

Bogdan
sumber
1
Kami juga dapat menambahkan shrinkparameter ketika fractionbersama-sama dengan padtidak menghasilkan hasil yang diinginkan.
Fei Yao