Як я можу встановити співвідношення сторін у matplotlib?


108

Я намагаюся зробити квадратний сюжет (за допомогою imshow), тобто співвідношення сторін 1: 1, але не можу. Жоден із цих робіт:

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

Схоже, дзвінки просто ігноруються (проблема, з якою часто я маю проблеми з matplotlib).


6
Ви спробували ax.axis('equal')випадково? Як усі казали, те, що ви робили, має працювати, але це ax.axisможе бути інший шлях, щоб спробувати вирішити.
Джо Кінгтон

Відповіді:


77

Третій раз чарівність. Я здогадуюсь, що це помилка, і відповідь Женя дозволяє виправити це в останній версії. У мене версія 0.99.1.1 і я створив таке рішення:

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

Це 'force.png': введіть тут опис зображення

Нижче наведені мої невдалі, але сподіваюсь, інформаційні спроби.

Другий відповідь:

Моя "оригінальна відповідь" нижче є надмірною, оскільки це робить щось подібне до axes.set_aspect(). Я думаю, ти хочеш використовувати axes.set_aspect('auto'). Я не розумію, чому це так, але він створює для мене графік квадратного зображення, наприклад, цей сценарій:

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

Створює графік зображення з "рівним" співвідношенням сторін: введіть тут опис зображення і один із "автоматичним" співвідношенням сторін: введіть тут опис зображення

Код, наданий нижче у "оригінальній відповіді", дає вихідну точку для явно контрольованого співвідношення сторін, але, здається, він ігнорується, коли викликається показ шоу.

Оригінальний відповідь:

Ось приклад програми, яка буде коригувати параметри субплоти, щоб отримати бажане співвідношення сторін:

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

Виходить така цифра: введіть тут опис зображення

Я можу собі уявити, що якщо у вас є кілька підпрограмів в межах рисунка, ви хочете включити кількість y і x підпрограми як параметри ключових слів (за замовчуванням до 1 кожного) до наданого розпорядку. Потім , використовуючи ці цифри і hspaceі wspaceключові слова, ви можете зробити все подзаговор мати правильне співвідношення сторін.


1
У випадках, коли get_imagesє порожній список (як це сталося б ax.plot([0,1],[0,2]), ви можете використовувати get_xlimіget_ylim
Joel

Мені здається, що це не вийде, якщо це зробити з журналом журналів. Я додав відповідь, які тести на це і обробляє. Не соромтеся включити це у свою відповідь, і тоді я зніму свою.
Джоель

1
Причина того, що аспект виглядає неоднаковою, полягає в тому, що рівний аспект означає, що візуальна відстань у х буде такою ж, як у. Якщо зображення квадратне, але сюжет dx та dy відрізняються, то це не співвідношення сторін 1: 1. Співвідношення сторін у цьому випадку буде dy / dx.
барт-кубріч

22

Яку matplotlibверсію ви запускаєте? Нещодавно мені довелося модернізувати 1.1.0і разом із цим add_subplot(111,aspect='equal')працює для мене.


1
Для мене добре працює у matplotlibверсії 2.0.2. jupyter notebookверсія 5.0.0. Дякую.
Сатіш

5

Після багаторічного успіху у відповідях вище, я виявив, що це більше не працює - але я знайшов робоче рішення для субплотів на

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

З повним кредитом, безумовно, автору вище (який, можливо, може розмістити тут), відповідні рядки:

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

Посилання також має чітко зрозуміле пояснення різних систем координат, які використовує matplotlib.

Дякую за всі отримані чудові відповіді - особливо @ Yann's, які залишаться переможцем.


3

вам слід спробувати фігаспект. Це працює для мене. З документів:

Створіть фігуру із заданим співвідношенням сторін. Якщо arg - число, використовуйте це співвідношення сторін. > Якщо arg - це масив, figaspect визначатиме ширину і висоту для фігури, яка б відповідала збереженню пропорцій масиву. Повертається ширина фігури, висота в дюймах. Обов’язково створіть осі з рівними та висотою, наприклад

Приклад використання:

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

Редагувати: Я не впевнений, що ви шукаєте. Вищевказаний код змінює полотно (розмір сюжету). Якщо ви хочете змінити розмір вікна matplotlib фігури, скористайтеся:

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

при цьому створюється вікно 5x1 (шхт).


Дякую за це - це має певний ефект у зміні співвідношення сторін полотна: Щоб бути більш конкретним, мені потрібно змінити співвідношення сторін самої фігури, що робити не так (форматування аполосів ..): fig = plt.figure (figsize = (plt.figaspect (2.0)))
jtlz2

3

Ця відповідь заснована на відповіді Янна. Він встановить співвідношення сторін для лінійних або журнальних журналів. Я використовував додаткову інформацію з https://stackoverflow.com/a/16290035/2966723, щоб перевірити, чи є осі лог-шкали.

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)

Очевидно, ви можете використовувати будь-яку версію, logяку хочете, я використав scipy, але numpyабо mathмає бути добре.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.