Đặt kích thước thanh màu Matplotlib để khớp với biểu đồ


160

Tôi không thể có được thanh màu trên các biểu đồ imshow như biểu đồ này có cùng chiều cao với biểu đồ, không sử dụng Photoshop sau khi thực tế. Làm thế nào để tôi có được chiều cao phù hợp?Ví dụ về sự không phù hợp kích thước thanh màu


Bạn đã thử các đề xuất từ stackoverflow.com/questions/16702479/ trên
lmjohns3

@ imjohns3 Không có gì trong bài đăng đó dường như làm bất cứ điều gì với thanh màu. Nó vẫn giữ nguyên kích thước cho dù tôi đặt gì. Tuy nhiên, nếu tôi đặt phân số và thu nhỏ, kích thước của biểu đồ sẽ thay đổi trong khi thanh màu giữ nguyên, cho đến khi chúng tôi quay lại với những gì tôi đã có, thì chúng sẽ ngừng làm bất cứ điều gì.
Elliot

Kiểm tra các tài liệu - matplotlib.org/api/colorbar_api.html - và sử dụng fractionhoặc lập luận shrink.
BoltzmannBrain

Câu trả lời:


194

Bạn có thể thực hiện việc này một cách dễ dàng với công cụ trục chính matplotlib .

Ví dụ từ trang được liên kết cũng hoạt động mà không sử dụng các ô con:

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)

nhập mô tả hình ảnh ở đây


1
Tôi không làm việc trong một subplot, vì vậy điều này không áp dụng.
Elliot

Sau khi mày mò nhiều, đã làm cho nó hoạt động. Có rất nhiều rắc rối khi tương tác với subplot_adjust, bạn phải nhận được các cuộc gọi ở đúng nơi tương đối với nhau.
Elliot

11
Điều này hơi thay đổi kích thước của đồ thị. Tôi có 4 trong một lưới 2x2, nhưng chỉ muốn hai bên phải có các thanh (tỷ lệ áp dụng theo hàng). Tuy nhiên điều này làm cho chúng không cùng kích thước. Tôi đã cố gắng không có cuộc gọi thanh màu (với cuộc gọi chia), nhưng tất nhiên điều này để lại một hộp trắng và số ở bên cạnh. Làm thế nào để tôi có được chúng có kích thước phù hợp mà không đặt các thanh trên tất cả chúng?
Elliot

@bogatron Thật không may, điều này không hoạt động với các trục được chiếu
Bogdan

Nếu bạn muốn thêm một tiêu đề bằng cách sử dụng plt.title, nó sẽ được hiển thị ở bên phải. Có cách nào để khắc phục điều này?
dùng2820579

224

Sự kết hợp này (và các giá trị gần với chúng) dường như "kỳ diệu" đối với tôi để giữ cho thanh màu được chia tỷ lệ theo cốt truyện, bất kể kích thước màn hình hiển thị.

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

Nó cũng không yêu cầu chia sẻ trục có thể đưa cốt truyện ra khỏi hình vuông.


4
Điều này có thể hoạt động trong một số trường hợp, nhưng nói chung là không. Hãy thử, ví dụ, vẽ một cái gì đó giống như trong câu hỏi ban đầu, có chiều rộng gấp đôi chiều cao.
Matthias

Tùy chọn phân số dường như vẫn hoạt động trong trường hợp bạn đề cập, nếu được chia tỷ lệ để phù hợp với chiều cao của cốt truyện. (mpl v1.4.3)
bầu trời

6
Đây là cách phổ quát duy nhất để làm điều đó. Các giải pháp với axex_grid1 sẽ không hoạt động đối với các trục được chiếu như GeoAxes.
Bogdan

OMG này là tuyệt vời. Cảm ơn bạn rất nhiều vì giải pháp
2D_

3
Đáp lại bình luận của @Matthias. Bạn có thể sửa cho trường hợp hình ảnh quá rộng bằng thủ thuật này: hình ảnh của bạn im_ratio = data.shape[0]/data.shape[1] plt.colorbar(im,fraction=0.046*im_ratio, pad=0.04)ở đâu data.
eindzl

29

@bogatron đã đưa ra câu trả lời được đề xuất bởi các tài liệu matplotlib , tạo ra chiều cao phù hợp, nhưng nó đưa ra một vấn đề khác. Bây giờ chiều rộng của thanh màu (cũng như khoảng cách giữa thanh màu và ô) thay đổi theo chiều rộng của ô. Nói cách khác, tỷ lệ khung hình của thanh màu không còn cố định nữa.

Để có được cả chiều cao phù hợp tỷ lệ khung hình nhất định, bạn phải đào sâu hơn một chút vào axes_grid1mô-đun bí ẩn .

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)

Lưu ý rằng điều này chỉ định chiều rộng của thanh màu ghi chiều cao của ô (trái ngược với chiều rộng của hình, như trước đây).

Khoảng cách giữa thanh màu và ô bây giờ có thể được chỉ định là một phần nhỏ của chiều rộng của thanh màu, đó là IMHO một số có ý nghĩa hơn nhiều so với một phần của chiều rộng hình.

cốt truyện hình ảnh với colorbar

CẬP NHẬT:

Tôi đã tạo một sổ ghi chép IPython về chủ đề này , nơi tôi đã đóng gói mã ở trên vào một chức năng có thể sử dụng lại dễ dàng:

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)

Nó có thể được sử dụng như thế này:

im = plt.imshow(np.arange(200).reshape((20, 10)))
add_colorbar(im)

1
Đây là một chức năng nhỏ thực sự hữu ích! Một lời cảnh báo là nó không hoạt động khi bạn muốn thêm nhiều bảng màu, vì chúng xuất hiện chồng lên nhau.
Hội trường David

22

Tôi đánh giá cao tất cả các câu trả lời ở trên. Tuy nhiên, giống như một số câu trả lời và ý kiến chỉ ra, các axes_grid1mô-đun có thể không GeoAxes địa chỉ, trong khi điều chỉnh fraction, pad, shrink, và các thông số tương tự khác có thể không nhất thiết phải đưa ra thứ tự rất chính xác, mà thực sự làm tôi bực mình. Tôi tin rằng việc đưa ra chính colorbaraxescó thể là một giải pháp tốt hơn để giải quyết tất cả các vấn đề đã được đề cập.

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)

Kết quả

nhập mô tả hình ảnh ở đây

Sau này, tôi thấy matplotlib.pyplot.colorbartài liệu chính thức cũng cung cấp axtùy chọn, đó là các trục hiện có sẽ cung cấp chỗ cho thanh màu. Do đó, nó rất hữu ích cho nhiều subplots, xem sau.

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)

Kết quả

nhập mô tả hình ảnh ở đây

Một lần nữa, bạn cũng có thể đạt được các hiệu ứng tương tự bằng cách chỉ định cax, một cách chính xác hơn từ quan điểm của tôi.

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)

Kết quả

nhập mô tả hình ảnh ở đây


@ HS-nebula Cảm ơn ý kiến ​​của bạn và tôi rất vui khi bạn thích nó. :)
Fei Yao

Câu trả lời thực sự tuyệt vời. Cảm ơn bạn!!
tập

11

Khi bạn tạo colorbarthử, sử dụng tham số phân số và / hoặc thu nhỏ.

Từ các tài liệu:

phần 0,15; một phần của các trục ban đầu được sử dụng cho colorbar

co lại 1,0; phân số để thu nhỏ thanh màu


1
Nếu tôi đặt thu nhỏ 1.0 và phân số thành bất cứ thứ gì, nó sẽ thu nhỏ biểu đồ, hoàn toàn không ảnh hưởng đến kích thước thanh màu, cho đến khi thay đổi phân số làm cho nó chính xác là những gì tôi đã có, tại thời điểm đó, việc thay đổi chúng sẽ ngừng làm bất cứ điều gì.
Elliot

Trường hợp chính xác là bạn chỉ định chúng, chúng phải là tham số cho colorbar()hàm hoặc phương thức.
Steve Barnes

Cảm ơn. chỉ cần xác định tham số thu nhỏ và nó hoạt động như ma thuật!
Mã hóa

11

Tất cả các giải pháp trên đều tốt, nhưng tôi thích cách tốt nhất của @ Steve và @ bejota vì chúng không liên quan đến các cuộc gọi ưa thích và mang tính phổ quát.

Theo phổ quát tôi có nghĩa là làm việc với bất kỳ loại trục bao gồm GeoAxes. Ví dụ: bạn đã chiếu các trục để ánh xạ:

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

một cuộc gọi đến

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

sẽ thất bại với: KeyException: map_projection

Do đó, cách phổ biến duy nhất để xử lý kích thước thanh màu với tất cả các loại trục là:

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

Làm việc với phân số từ 0,035 đến 0,046 để có kích thước tốt nhất của bạn. Tuy nhiên, các giá trị cho phân số và paddig sẽ cần được điều chỉnh để phù hợp nhất với cốt truyện của bạn và sẽ khác nhau tùy theo hướng của thanh màu nằm ở vị trí thẳng đứng hay nằm ngang.


1
Chúng ta cũng có thể thêm shrinktham số khi fractioncùng với padkhông tạo ra kết quả mong muốn đủ.
Fei Yao
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.