Получение одинакового размера подзадачи с использованием matplotlib imshow и разброса

Я пытаюсь построить изображение (используя matplotlib.imshow) и график рассеяния на одном и том же рисунке. При попытке этого изображения изображение оказывается меньше, чем график рассеяния. Ниже показан небольшой пример кода:

import matplotlib.pyplot as plt
import numpy as np

image = np.random.randint(100,200,(200,200))
x = np.arange(0,10,0.1)
y = np.sin(x)

fig, (ax1, ax2) = plt.subplots(1,2)
ax1.imshow(image)
ax2.scatter(x,y)

plt.show()

Что дает следующий рисунок:

введите описание изображения здесь

Как я могу получить две подсловы одинаковой высоты? (и, по-видимому, ширина)

Я попытался использовать gridspec, как показано в this:

fig=plt.figure()
gs=GridSpec(1,2)

ax1=fig.add_subplot(gs[0,0])
ax2=fig.add_subplot(gs[0,1])
ax1.imshow(image)
ax2.scatter(x,y)

Но это дает тот же результат. Я также попытался настроить размеры подзаголовков вручную, используя:

fig = plt.figure()
ax1 = plt.axes([0.05,0.05,0.45,0.9])
ax2 = plt.axes([0.55,0.19,0.45,0.62])

ax1.imshow(image)
ax2.scatter(x,y)

В результате проб и ошибок я могу получить два подзаголовка до нужного размера, хотя любое изменение общего размера фигуры будет означать, что подзаголовки больше не будут иметь одинаковый размер.

Есть ли способ сделать график imshow и scatter таким же размером на фигуре без изменения размеров осей вручную?

Я использую Python 2.7 и matplotlib 2.0.0

Ответ 1

Не совсем понятно, какой у вас желаемый результат.

  1. Вы можете использовать автоматический аспект на изображении

    ax.imshow(z, aspect="auto")
    

    enter image description here

  2. Или вы можете установить аспект линейного графика в зависимости от пределов его оси так, чтобы он получал тот же размер, что и изображение (в случае, если изображение имеет равные размеры x и y)

    asp = np.diff(ax2.get_xlim())[0] / np.diff(ax2.get_ylim())[0]
    ax2.set_aspect(asp)
    

    enter image description here Полный код:

    import numpy as np
    import matplotlib.pyplot as plt
    
    x = np.linspace(0,10,20)
    y = np.sin(x)
    z = np.random.rand(100,100)
    
    fig, (ax, ax2) = plt.subplots(ncols=2)
    
    ax.imshow(z)
    ax2.plot(x,y, marker=".")
    
    asp = np.diff(ax2.get_xlim())[0] / np.diff(ax2.get_ylim())[0]
    ax2.set_aspect(asp)
    
    plt.show()
    

    Если изображение не имеет равных пределов (не является квадратным), его все равно необходимо разделить на аспект изображения:

    asp = np.diff(ax2.get_xlim())[0] / np.diff(ax2.get_ylim())[0]
    asp /= np.abs(np.diff(ax1.get_xlim())[0] / np.diff(ax1.get_ylim())[0])
    ax2.set_aspect(asp)
    
  3. Более сложные решения:

    • Этот ответ для использования параметров подзаговора для достижения определенного аспекта.

    • Если вы хотите использовать mpl_toolkits и испачкать руки, этот ответ будет хорошим чтением.

Ответ 2

У меня была такая же проблема, и я задал очень похожий вопрос в SO. Решение, предложенное @ImportanceOfBeingErnest, работало как прелесть для меня, но для полноты я хотел бы упомянуть довольно простой обходной путь, который мне предлагали применить (кредит для @Yilun Zhang), прежде чем мой вопрос был отмечен как точный дубликат этого один:

Проблема заключается в том, что высота области графика слишком велика, и это оставляет пустое место на изображении.

Если вы измените свой код на:

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

тогда вы получите желаемый результат:

Желаемый результат

Ответ 3

Вот код, который я использую:

fig, axis_array = plt.subplots(1, 2, figsize=(chosen_value, 1.05 * chosen_value / 2),
                               subplot_kw={'aspect': 1})

Я явно выбираю, что на моей фигуре будет 2 подзаголовка, и что эта цифра будет выбрана равной значению, а каждая подзадача будет примерно вдвое меньше, чем ширина, и что подзаголовки будут иметь соотношение сторон 1 ( т.е. они будут квадратными). Размер фигуры - это конкретное соотношение, которое заставляет интервал.