Matplotlib setting `axes` object with `imshow` causes y-axis to become variable

依然范特西╮ 提交于 2019-12-24 07:58:28

问题


Description

I have began refactoring some code based on the future warning of matplotlib, to re-use the initially defined axes object. However, I noticed that whenever I was re-using my axes object, the image size would be variable. Since, I have managed to isolate the problem to the axes.imshow method as after using imshow, the y-axis of any subsequent drawing on that axes has a y-axis that seems to rescale.

The feeling I have is that the y-axis scale is retained from the initial image that is plotted using imshow (I thought that axes.clear should reset this). Specifically in the below examples, shuffling plots some data spanning ~ 9.90 to 10.10 but because the original image spanned form 0 to 50 the y-axis is barely visible.

Below are first two screenshots of the expected and then 'bugged' behaviour, followed by an MVCE that has two sections that can be toggled to get the expected or 'bugged' behaviour:

Images

  1. Splash without imshow:

  2. Screen after 'Foo -> Shuffle' (Expected behaviour):

  3. Splash with imshow:

  4. Screen after 'Foo -> Shuffle' (unexpected behaviour):

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

Question

What is going on here, specifically what is causing the image to appear so differently and what can be done about it?


回答1:


When no argument is given for aspect, it defaults to None. From the documentation:

If None, default to rc image.aspect value

Therefore if no argument is given to imshow, it will use whatever the rcParam for "image.aspect" is, which you can find by doing:

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

A fix to your problem would be to set it to "auto" in your shuffle function using 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()

If you don't mind changing the aspect ratio of imshow, there is also an aspect= argument:

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


来源:https://stackoverflow.com/questions/52202758/matplotlib-setting-axes-object-with-imshow-causes-y-axis-to-become-variable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!