问题
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
Splash without
imshow
:Screen after 'Foo -> Shuffle' (Expected behaviour):
Splash with
imshow
: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