【问题标题】:Matplotlib setting `axes` object with `imshow` causes y-axis to become variableMatplotlib 使用 `imshow` 设置 `axes` 对象会导致 y 轴变为变量
【发布时间】:2019-02-11 15:21:14
【问题描述】:

说明

我已经开始根据 matplotlib 的未来警告重构一些代码,以重用最初定义的 axes 对象。但是,我注意到每当我重新使用我的axes 对象时,图像大小都会发生变化。因为,在使用imshow 之后,我设法将问题隔离到axes.imshow 方法,该轴上任何后续绘图的y 轴都有一个似乎重新缩放的y 轴。

我的感觉是 y 轴刻度从使用imshow 绘制的初始图像中保留下来(我认为axes.clear 应该重置它)。特别是在下面的示例中,改组绘制了一些跨越 ~ 9.90 到 10.10 的数据,但由于原始图像跨越 0 到 50 的形式,y 轴几乎不可见。

下面是预期行为的前两个屏幕截图,然后是“错误”行为,然后是一个 MVCE,其中有两个部分可以切换以获得预期或“错误”行为:

图片

  1. 没有imshow的飞溅:

  2. “Foo -> Shuffle”后的屏幕(预期行为):

  3. 使用imshow 飞溅:

  4. “Foo -> Shuffle”之后的屏幕(意外行为):

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

问题

这里发生了什么,特别是是什么导致图像看起来如此不同以及可以采取什么措施?

【问题讨论】:

    标签: python-3.x matplotlib tkinter tkinter-canvas


    【解决方案1】:

    aspect 没有参数时,默认为None。来自documentation

    如果没有,默认为 rc image.aspect 值

    因此,如果没有为 imshow 提供参数,它将使用 "image.aspect" 的任何 rcParam,您可以通过以下操作找到:

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

    【讨论】:

    • 我没有意识到imshow改变了方面,这确实导致了问题。但是,我选择将其设置在初始的imshow 行中,如下所示:self.axes.imshow(Z, aspect='auto')
    • @BasJansen 是的,这也是一个选项。我也更新了答案
    • 在大多数情况下,matplotlib 中的None 表示“默认值”。对于imshow,默认纵横比为"equal"。方面传播到轴。设置轴方面后,它将保留该设置,直到您再次更改它。这就是这个答案通过self.axes.set_aspect("auto") 所做的。
    • @ImportanceOfBeingErnest 所以如果imshow 默认为“相等”,这是否意味着它会覆盖rcParams["image.aspect"]
    • 不,抱歉。当然默认为rcParams["image.aspect"],默认为"equal"
    猜你喜欢
    • 2013-08-16
    • 1970-01-01
    • 1970-01-01
    • 2018-06-23
    • 2011-06-05
    • 1970-01-01
    • 2019-02-11
    • 1970-01-01
    相关资源
    最近更新 更多