Làm cách nào để đặt tỷ lệ khung hình trong matplotlib?


108

Tôi đang cố tạo một ô vuông (sử dụng imshow), tức là tỷ lệ co 1: 1, nhưng tôi không thể. Không có tác dụng nào trong số này:

import matplotlib.pyplot as plt

ax = fig.add_subplot(111,aspect='equal')
ax = fig.add_subplot(111,aspect=1.0)
ax.set_aspect('equal')
plt.axes().set_aspect('equal')

Có vẻ như các cuộc gọi đang bị bỏ qua (một vấn đề mà tôi thường gặp với matplotlib).


6
Bạn đã thử ax.axis('equal'), tình cờ? Như mọi người đã nói, những gì bạn đã làm sẽ hiệu quả, nhưng ax.axiscó thể là một lộ trình khác để cố gắng tìm cách giải quyết.
Joe Kington

Câu trả lời:


77

Lần thứ ba quyến rũ. Tôi đoán rằng đây là một lỗi và câu trả lời của Zhenya cho thấy nó đã được sửa trong phiên bản mới nhất. Tôi có phiên bản 0.99.1.1 và tôi đã tạo giải pháp sau:

import matplotlib.pyplot as plt
import numpy as np

def forceAspect(ax,aspect=1):
    im = ax.get_images()
    extent =  im[0].get_extent()
    ax.set_aspect(abs((extent[1]-extent[0])/(extent[3]-extent[2]))/aspect)

data = np.random.rand(10,20)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data)
ax.set_xlabel('xlabel')
ax.set_aspect(2)
fig.savefig('equal.png')
ax.set_aspect('auto')
fig.savefig('auto.png')
forceAspect(ax,aspect=1)
fig.savefig('force.png')

Đây là 'force.png': nhập mô tả hình ảnh ở đây

Dưới đây là những nỗ lực không thành công, nhưng hy vọng có nhiều thông tin.

Câu trả lời thứ hai:

'Câu trả lời ban đầu' của tôi bên dưới là quá mức cần thiết, vì nó hoạt động tương tự như axes.set_aspect(). Tôi nghĩ rằng bạn muốn sử dụng axes.set_aspect('auto'). Tôi không hiểu tại sao lại xảy ra trường hợp này, nhưng nó tạo ra một âm mưu hình ảnh vuông cho tôi, ví dụ như tập lệnh này:

import matplotlib.pyplot as plt
import numpy as np

data = np.random.rand(10,20)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data)
ax.set_aspect('equal')
fig.savefig('equal.png')
ax.set_aspect('auto')
fig.savefig('auto.png')

Tạo ra một âm mưu hình ảnh có tỷ lệ khung hình 'bằng nhau': nhập mô tả hình ảnh ở đây và một âm mưu có tỷ lệ khung hình 'tự động': nhập mô tả hình ảnh ở đây

Mã được cung cấp bên dưới trong 'câu trả lời ban đầu' cung cấp điểm khởi đầu cho tỷ lệ khung hình được kiểm soát rõ ràng, nhưng nó dường như bị bỏ qua khi một imshow được gọi.

Câu trả lời gốc:

Dưới đây là một ví dụ về một quy trình sẽ điều chỉnh các thông số của subplot để bạn có được tỷ lệ khung hình mong muốn:

import matplotlib.pyplot as plt

def adjustFigAspect(fig,aspect=1):
    '''
    Adjust the subplot parameters so that the figure has the correct
    aspect ratio.
    '''
    xsize,ysize = fig.get_size_inches()
    minsize = min(xsize,ysize)
    xlim = .4*minsize/xsize
    ylim = .4*minsize/ysize
    if aspect < 1:
        xlim *= aspect
    else:
        ylim /= aspect
    fig.subplots_adjust(left=.5-xlim,
                        right=.5+xlim,
                        bottom=.5-ylim,
                        top=.5+ylim)

fig = plt.figure()
adjustFigAspect(fig,aspect=.5)
ax = fig.add_subplot(111)
ax.plot(range(10),range(10))

fig.savefig('axAspect.png')

Điều này tạo ra một con số như vậy: nhập mô tả hình ảnh ở đây

Tôi có thể tưởng tượng nếu bạn có nhiều ô con trong hình, bạn sẽ muốn bao gồm số ô con y và x làm tham số từ khóa (mặc định là 1 ô) cho quy trình được cung cấp. Sau đó, sử dụng những con số đó và hspacewspacetừ khóa, bạn có thể làm cho tất cả các ô phụ có tỷ lệ khung hình chính xác.


1
Đối với trường hợp get_imageslà một danh sách rỗng (như sẽ xảy ra với ax.plot([0,1],[0,2]), bạn có thể sử dụng get_xlimget_ylim
Joel

Đối với tôi, nó sẽ không hoạt động nếu được thực hiện với logscale. Tôi đã thêm một câu trả lời để kiểm tra điều đó và xử lý nó. Vui lòng kết hợp điều đó vào câu trả lời của bạn và sau đó tôi sẽ xóa của tôi.
Joel

1
Lý do mà khía cạnh trông không bằng nhau là vì khía cạnh bằng nhau có nghĩa là khoảng cách thị giác theo x sẽ giống y. Nếu hình ảnh là hình vuông, nhưng biểu đồ dx và dy khác nhau, thì đó không phải là tỷ lệ khung hình 1: 1. Tỷ lệ khung hình sẽ là dy / dx trong trường hợp đó.
bart cubrich 21/02/19

22

Là gì matplotlibphiên bản bạn đang chạy? Gần đây tôi đã phải nâng cấp lên 1.1.0và với nó, add_subplot(111,aspect='equal')hoạt động cho tôi.


1
Hoạt động tốt cho tôi trong matplotlibphiên bản 2.0.2. jupyter notebookphiên bản 5.0.0. Cảm ơn.
Sathish

5

Sau nhiều năm thành công với các câu trả lời ở trên, tôi nhận thấy điều này không hoạt động trở lại - nhưng tôi đã tìm thấy giải pháp hoạt động cho các ô phụ tại

https://jdhao.github.io/2017/06/03/change-aspect-ratio-in-mpl

Tất nhiên, với đầy đủ tín dụng cho tác giả ở trên (người có lẽ có thể đăng ở đây), các dòng liên quan là:

ratio = 1.0
xleft, xright = ax.get_xlim()
ybottom, ytop = ax.get_ylim()
ax.set_aspect(abs((xright-xleft)/(ybottom-ytop))*ratio)

Liên kết cũng có lời giải thích rõ ràng về các hệ tọa độ khác nhau được sử dụng bởi matplotlib.

Cảm ơn tất cả các câu trả lời tuyệt vời đã nhận được - đặc biệt là @ Yann's sẽ vẫn là người chiến thắng.


3

bạn nên thử với hình tượng. Nó làm việc cho tôi. Từ các tài liệu:

Tạo một hình với tỷ lệ khung hình được chỉ định. Nếu arg là một con số, sử dụng mà tỉ lệ. > Nếu arg là một mảng, figaspect sẽ xác định chiều rộng và chiều cao cho một nhân vật mà sẽ phù hợp với mảng bảo tồn tỷ lệ khía cạnh. Chiều rộng hình, chiều cao tính bằng inch được trả về. Đảm bảo tạo một trục có chiều cao và bằng nhau, ví dụ:

Ví dụ sử dụng:

  # make a figure twice as tall as it is wide
  w, h = figaspect(2.)
  fig = Figure(figsize=(w,h))
  ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
  ax.imshow(A, **kwargs)

  # make a figure with the proper aspect for an array
  A = rand(5,3)
  w, h = figaspect(A)
  fig = Figure(figsize=(w,h))
  ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
  ax.imshow(A, **kwargs)

Chỉnh sửa: Tôi không chắc chắn về những gì bạn đang tìm kiếm. Đoạn mã trên thay đổi canvas (kích thước ô). Nếu bạn muốn thay đổi kích thước của cửa sổ matplotlib của hình, hãy sử dụng:

In [68]: f = figure(figsize=(5,1))

điều này tạo ra một cửa sổ 5x1 (wxh).


Cảm ơn vì điều này - nó thực sự có một số tác dụng, trong việc thay đổi tỷ lệ khung hình của canvas: Để cụ thể hơn, tôi cần thay đổi tỷ lệ khung hình của chính hình vẽ, điều này không thực hiện được (định dạng apols ..): fig = plt.figure (figsize = (plt.figaspect (2.0)))
jtlz2

3

Câu trả lời này dựa trên câu trả lời của Yann. Nó sẽ đặt tỷ lệ co cho các đồ thị tuyến tính hoặc log-log. Tôi đã sử dụng thông tin bổ sung từ https://stackoverflow.com/a/16290035/2966723 để kiểm tra xem các trục có quy mô log hay không.

def forceAspect(ax,aspect=1):
    #aspect is width/height
    scale_str = ax.get_yaxis().get_scale()
    xmin,xmax = ax.get_xlim()
    ymin,ymax = ax.get_ylim()
    if scale_str=='linear':
        asp = abs((xmax-xmin)/(ymax-ymin))/aspect
    elif scale_str=='log':
        asp = abs((scipy.log(xmax)-scipy.log(xmin))/(scipy.log(ymax)-scipy.log(ymin)))/aspect
    ax.set_aspect(asp)

Rõ ràng là bạn có thể sử dụng bất kỳ phiên bản nào logbạn muốn, tôi đã sử dụng scipy, nhưng numpyhoặc mathsẽ ổn.

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.