Matplotlib'de en boy oranını nasıl ayarlayabilirim?


108

Bir kare çizim yapmaya çalışıyorum (imshow kullanarak), yani 1: 1 en boy oranı, ama yapamıyorum. Bunların hiçbiri çalışmıyor:

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')

Görünüşe göre aramalar yok sayılıyor (matplotlib ile sık sık yaşadığım bir sorun).


6
ax.axis('equal')Şans eseri denedin mi? Herkesin dediği gibi, yaptığınız şey işe yaramalı, ancak ax.axisgeçici bir çözüm için denemenin başka bir yolu olabilir.
Joe Kington

Yanıtlar:


77

Üçüncü kat cazibe. Benim tahminim bu bir hata olduğunu ve olmasıdır ZHenya cevabı o son sürümünde onarıldı göstermektedir. 0.99.1.1 sürümüne sahibim ve aşağıdaki çözümü oluşturdum:

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')

Bu "force.png" dir: görüntü açıklamasını buraya girin

Başarısız, ancak umarım bilgilendirici girişimlerim aşağıdadır.

İkinci Cevap:

Aşağıdaki 'orijinal cevabım', benzer bir şey yaptığı için abartılı axes.set_aspect(). Sanırım kullanmak istiyorsun axes.set_aspect('auto'). Neden böyle olduğunu anlamıyorum, ama benim için kare bir görüntü çizimi oluşturuyor, örneğin şu komut dosyası:

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')

En boy oranına 'eşit' görüntü açıklamasını buraya girin ve 'otomatik' en boy oranına sahip bir görüntü grafiği üretir : görüntü açıklamasını buraya girin

Aşağıda 'orijinal cevapta' verilen kod, açıkça kontrol edilen bir en-boy oranı için bir başlangıç ​​noktası sağlar, ancak bir imshow çağrıldığında göz ardı edilecek gibi görünüyor.

Orijinal Cevap:

İstenilen en boy oranını elde edebilmeniz için alt alan parametrelerini ayarlayacak bir rutin örneği aşağıda verilmiştir:

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')

Bu, şöyle bir rakam üretir: görüntü açıklamasını buraya girin

Şekilde birden fazla alt grafiğiniz varsa, sağlanan rutine anahtar kelime parametreleri olarak (her biri 1 varsayılan olarak) y ve x alt nokta sayısını dahil etmek isteyeceğinizi hayal edebiliyorum. Sonra bu sayıları kullanarak hspaceve wspaceanahtar kelimeleri, tüm subplots doğru orana sahip yapabilirsiniz.


1
get_imagesListenin boş olduğu durumlar için (olduğu gibi ax.plot([0,1],[0,2]), get_xlimve kullanabilirsinizget_ylim
Joel

Bana öyle geliyor ki, logscale ile yapılırsa bu işe yaramayacak. Bunu test eden ve ele alan bir cevap ekledim. Bunu cevabınıza dahil etmekten çekinmeyin, sonra benimkini çıkaracağım.
Joel

1
Görünüşün eşitsiz görünmesinin nedeni, eşit boyutun x'teki görsel mesafenin y ile aynı olacağı anlamına gelmesidir. Görüntü kareyse, ancak dx ve dy çizimleri farklıysa, bu 1: 1 en boy oranı değildir. Bu durumda en boy oranı dy / dx olacaktır.
bart cubrich

22

Çalıştırdığınız matplotlibsürüm nedir ? Son zamanlarda benim için çalışıyor 1.1.0ve bununla birlikte yükseltme yapmak zorunda kaldım add_subplot(111,aspect='equal').


1
Benim için iyi çalışır matplotlibsürümü 2.0.2. jupyter notebookversiyon 5.0.0. Teşekkürler.
Sathish

5

Yukarıdaki cevaplarla yıllarca süren başarıdan sonra, bunun tekrar işe yaramayacağını buldum - ancak alt noktalar için çalışan bir çözüm buldum

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

Elbette yukarıdaki yazara (belki buraya yazmayı tercih edebilir) tam notla, ilgili satırlar:

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

Bağlantı ayrıca matplotlib tarafından kullanılan farklı koordinat sistemlerinin kristal netliğinde bir açıklamasına sahiptir.

Alınan tüm harika yanıtlar için teşekkürler - özellikle de kazanan olmaya devam edecek olan Yann's.


3

figaspect ile denemelisiniz. Benim için çalışıyor. Dokümanlardan:

Belirtilen en boy oranına sahip bir şekil oluşturun. Eğer Arg bir sayı, en boy oranı bu kullanılmasıdır. > Eğer arg bir dizi ise figaspect, en-boy oranını koruyarak diziye sığacak bir şeklin genişliğini ve yüksekliğini belirleyecektir. Figür genişliği, yüksekliği inç olarak döndürülür. Eşit ve yüksekliğe sahip eksenler oluşturduğunuzdan emin olun, örn.

Örnek kullanım:

  # 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)

Düzenleme: Ne aradığınızdan emin değilim. Yukarıdaki kod, tuvali (çizim boyutunu) değiştirir. Şeklin matplotlib penceresinin boyutunu değiştirmek isterseniz, şunu kullanın:

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

bu 5x1'lik (gxy) bir pencere oluşturur.


Bunun için teşekkürler - tuvalin en boy oranını değiştirmede bir etkisi var: Daha spesifik olmak gerekirse, şeklin kendisinin en boy oranını değiştirmem gerekiyor, ki bunu yapmamak (apols formatting ..): fig = plt.figure (figsize = (plt.figaspect (2.0)))
jtlz2

3

Bu cevap, Yann'ın cevabına dayanmaktadır. Doğrusal veya log-log grafikler için en boy oranını ayarlayacaktır. Eksenlerin günlük ölçekli olup olmadığını test etmek için https://stackoverflow.com/a/16290035/2966723 adresinden ek bilgiler kullandım .

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)

Açıkçası, istediğiniz herhangi bir sürümünü kullanabilirsiniz log, kullandım scipy, ama numpyya mathda iyi olmalı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.