Как я могу установить соотношение сторон в matplotlib? - PullRequest
93 голосов
/ 01 ноября 2011

Я пытаюсь сделать квадратный сюжет (используя 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).

Ответы [ 4 ]

65 голосов
/ 01 ноября 2011

третий раз очарование. Я предполагаю, что это ошибка, и ответ Жени предполагает, что она исправлена ​​в последней версии. У меня версия 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': enter image description here

Ниже приведены мои неудачные, но, надеюсь, информативные попытки.

Второй ответ:

Мой «оригинальный ответ» ниже излишний, так как он делает что-то похожее на 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')

Создает изображение с «равным» соотношением сторон: enter image description here и один с «автоматическим» соотношением сторон: enter image description here

Код, приведенный ниже в «исходном ответе», обеспечивает исходную точку для явно контролируемого соотношения сторон, но, похоже, он игнорируется при вызове imshow.

Оригинальный ответ:

Вот пример подпрограммы, которая настроит параметры подзаговора так, чтобы вы получили желаемое соотношение сторон:

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

Это дает такую ​​фигуру: enter image description here

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

19 голосов
/ 01 ноября 2011

Какую версию matplotlib вы используете?Мне недавно пришлось обновиться до 1.1.0, и с ним add_subplot(111,aspect='equal') работает для меня.

3 голосов
/ 01 ноября 2011

вы должны попробовать с Figaspect.Меня устраивает.Из документов:

Создать фигуру с заданным соотношением сторон.Если 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 (wxh).

2 голосов
/ 16 июля 2017

Этот ответ основан на ответе Янна. Он установит соотношение сторон для линейных или логарифмических участков. Я использовал дополнительную информацию из 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 должно быть в порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...