Matplotlib, устанавливающий объект `axes` с помощью` imshow`, заставляет ось y становиться переменной - PullRequest
0 голосов
/ 06 сентября 2018

Описание

Я начал рефакторинг некоторого кода на основе будущего предупреждения matplotlib, чтобы повторно использовать изначально определенный объект axes. Однако я заметил, что всякий раз, когда я повторно использовал мой axes объект, размер изображения был бы переменным. С тех пор мне удалось изолировать проблему с помощью метода axes.imshow, так как после использования imshow ось Y любого последующего чертежа на этих осях имеет ось Y, которая, по-видимому, масштабируется.

У меня такое ощущение, что шкала оси Y сохраняется из исходного изображения, построенного с помощью imshow (я думал, что axes.clear должно сбросить это). В частности, в приведенных ниже примерах перетасовывание отображает некоторые данные, охватывающие ~ 9,90–10,10, но поскольку исходное изображение в диапазоне от 0 до 50, ось y едва видна.

Ниже приведены два первых снимка экрана ожидаемого и затем «ошибочного» поведения, за которым следует MVCE с двумя разделами, которые можно переключать для получения ожидаемого или «ошибочного» поведения:

Изображения

  1. Всплеск без imshow: enter image description here

  2. Экран после 'Foo -> Shuffle' (ожидаемое поведение): enter image description here

  3. Всплеск с imshow: enter image description here

  4. Экран после 'Foo -> Shuffle' (неожиданное поведение): enter image description here

MVCE

from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg
)
import tkinter as tk
from matplotlib import image, figure
from numpy import random, linspace
from os import path, getcwd
from pylab import get_cmap

class Foo(object):
    @classmethod
    def run(cls):
        root = tk.Tk()
        Foo(root)
        root.mainloop()

    def __init__(self, master):
        # Figure & canvas
        self.fig = figure.Figure(figsize=(5,5))
        self.axes = self.fig.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.fig, master=master)
        self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=tk.YES)

        # Splash image (This 'bugs')
        Z = random.random((50,50))
        self.axes.imshow(Z, cmap=get_cmap("Spectral"), interpolation='nearest')
        self.canvas.draw()

        # Dummy start data (This Works)
        #self.axes.plot(random.normal(10,0.05,100))
        #self.canvas.draw()

        # MENU
        menu = tk.Menu(master)
        master.config(menu=menu)
        test_menu = tk.Menu(menu, tearoff=0)
        menu.add_cascade(label="Foo", menu=test_menu)
        test_menu.add_command(label="Shuffle",
                              command=self.shuffle)
        test_menu.add_command(label="Add",
                              command=self.add)

    def add(self):
        x_data = linspace(0,10, 1000)
        y_data = random.normal(x_data)
        self.axes.plot(x_data, y_data)
        self.canvas.draw()

    def shuffle(self):
        self.axes.clear()
        self.axes.plot(random.normal(10,0.05,100))
        self.canvas.draw()


if __name__ == "__main__":
   Foo.run()

Вопрос

Что здесь происходит, в частности, что заставляет изображение выглядеть по-другому и что с этим можно сделать?

1 Ответ

0 голосов
/ 06 сентября 2018

Если для aspect не задан аргумент, по умолчанию используется None. Из документации :

Если нет, по умолчанию используется значение rc image.aspect

Следовательно, если imshow не передан аргумент, он будет использовать любой параметр rcParam для «image.aspect», который вы можете найти, выполнив:

print (plt.rcParams["image.aspect"])  # default is "equal"

Решением вашей проблемы было бы установить его на «авто» в вашей функции shuffle, используя axes.set_aspect():

def shuffle(self):
    self.axes.clear()
    self.axes.plot(random.normal(10,0.05,100))
    self.axes.set_aspect("auto")
    self.canvas.draw()

Если вы не возражаете против изменения соотношения сторон imshow, есть также аргумент aspect=:

self.axes.imshow(Z, cmap=get_cmap("Spectral"), interpolation='nearest', aspect="auto")
...