The following is a simplified example of my code. The idea behind this class is to show the figure only when the show method is executed.
# my_module.py
import matplotlib.pyplot as plt
import numpy as np
class Test:
def __init__(self):
self._fig = plt.figure()
self.ax = self._fig.add_subplot(1, 1, 1)
def show(self):
x = np.linspace(0, 10, 100)
y = np.sin(x)
self.ax.plot(x, y)
self._fig.tight_layout()
self._fig.show()
The code works as expected when it is executed from a Python shell or ipython. However, if I run this inside a Jypter Notebook:
from my_module import Test
t = Test()
At this point, an empty figure is visualized on the screen. I don't want that! Now, I tried to insert plt.close(self._fig) inside __init__, but then when I run t.show() I get UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.
I also tried to load %matplotlib widget with the previous edit plt.close(self._fig). The pictures is only shown when show is called, but it is just a picture with no interactive frame.
Another option would be to rewrite the class in such a way that the figure is created inside the show method. This is far from optimal as I would need to re-adjust my tests.
Are there any other ways to get it working correctly on all shells?
In the original post I've done two mistakes.
First, the figure was instantiated into the __init__ method, then the show method was called. In an interactive environment, once the figure is created it will be shown on the screen. We could turn off that behaviour with plt.ioff(), but then two things can happen:
If %matplotlib widget was executed, the figure will show up only once when calling t.show().
Otherwise, no plot will be shown on the screen when calling t.show().
Hence, plt.ioff() is not a valid solution. Instead, the figure must be instantiated when t.show() is executed.
The second mistake I did was to use self._fig.show(). Remember, in a interactive environment the figure is shown as soon as it is instantiated. Then, the previous command shows the figure a second time! Instead, I have to use plt.show(), which only display the figure once.
Here is the correct code example:
import matplotlib.pyplot as plt
import numpy as np
class Test:
def __init__(self):
# init some attributes
pass
def show(self):
self._fig = plt.figure()
self.ax = self._fig.add_subplot(1, 1, 1)
x = np.linspace(0, 10, 100)
y = np.sin(x)
self.ax.plot(x, y)
self._fig.tight_layout()
plt.show()
t = Test() # no figure is shown
t.show() # figure is shown
Related
I have a class that owns some matplotlib figures, axes, artists, etc. It has functions for manipulating and displaying these that all work fine when working with instances of the class.
However, if a user wants to make some separate matplotlib plots in, say, another cell of a notebook that contains instances of my class, all the class's figures get displayed when the user calls plt.show() to display their own figures.
I'm using ipympl, %matplotlib widget, and setting plt.ioff().
Is there a way for me to set my figures so that they are not displayed when plt.show() is called?
Example: Consider these two Jupyter Notebook cells (have to be split for first figure to display)
%matplotlib widget
import matplotlib.pyplot as plt
plt.ioff()
class interactiveplot(object):
def __init__(self, x, y):
plt.ioff()
self.fig,self.ax = plt.subplots(figsize=(2,2))
self.plot, = self.ax.plot(x,y)
def update(self,x,y):
self.plot.set_data(x,y)
self.fig.canvas.draw()
def show(self):
return self.fig.canvas
#create class instance
test = interactiveplot([1,2,3,4],[4,1,5,7])
#display figure
test.show()
#Change data in displayed figure
test.update([2,3],[6,5])
#display a plot of something totally unrelated
fig,ax = plt.subplots(figsize=(2,2))
ax.scatter([2.3,3.4],[34,23])
plt.show()
#Both test.fig and fig are displayed! I only want to see fig!
I'm trying to control the display of a scatter plot with a checkbox. When I built it using the interact function it worked as expected. The plot was shown or hidden based on the value in the checkbox.
import matplotlib.pyplot as plt
from ipywidgets import interact, widgets
%matplotlib inline
def on_change(Display):
if Display == True:
plt.scatter(x,y)
plt.show()
return Display
interact(on_change, Display=False);
When I tried to do the same thing using the observe function every time I clicked on the checkbox I get an additional plot displayed below. What do I need to do to get it to redraw the same plot so it works like the example above?
I suppose something in the interact example is clearing the display but it's not clear how to do this manually.
import matplotlib.pyplot as plt
from ipywidgets import interact, widgets
%matplotlib inline
x = [1,2,3,4,5,6,7,8]
y = [5,2,4,2,1,4,5,2]
def on_change(change):
if change['new'] == True:
scat = plt.scatter(x,y)
plt.show()
cb = widgets.Checkbox(False, description = "Display")
cb.observe(on_change, names='value')
display(cb)
A couple of alterations I made to your example to hopefully demonstrate what you want. I have taken a more object-oriented route, not sure if you specifically wanted to avoid it but it helps achieve your desired outcome, it seems like you are moving towards a simple GUI here.
1) Include an Output widget (out) - basically a cell output which you can display like a normal widget. You can use a context manager block (with out:) when you want to print to that specific output widget. You can also clear the widget with out.clear_output()
2) Use the object oriented interface in matplotlib rather than using plt. I find this easier to control which plots are displayed and in which location at the right times.
temporarily suspend the interactive matplotlib with plt.ioff()
Create your figure and axis with fig, ax = plt.subplots(). NB figures can have multiple axes/subplots but we only need one.
'plot' the scatter data to your axis using ax.scatter(x,y), but this won't cause it to appear.
Explicitly display the figure with display(fig).
I'm assuming you want your figure to be replotted each time you check the box, so I have included it in the observe function. If your figure doesn't change, it would make sense to move it outside of the loop.
import matplotlib.pyplot as plt
from ipywidgets import interact, widgets
%matplotlib inline
out = widgets.Output()
x = [1,2,3,4,5,6,7,8]
y = [5,2,4,2,1,4,5,2]
def on_change(change):
if change['new'] == True:
with out:
plt.ioff()
fig,ax = plt.subplots()
ax.scatter(x,y)
display(fig)
else:
out.clear_output()
cb = widgets.Checkbox(False, description = "Display")
cb.observe(on_change, names='value')
display(cb)
display(out)
I'm writing a Python GUI for the first time to plot some data, and have imported the following modules/commands to do so
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.ttk import *
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.cm import get_cmap
from matplotlib.pyplot import figure
from scipy.interpolate import griddata
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
Searching the internet, I found some code that worked to get my plot embedded in the GUI:
fig = figure()
fig.add_subplot(111).pcolormesh(X, Y, Z, cmap = get_cmap('BuPu'))
canvas = FigureCanvasTkAgg(fig, master = window) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side = TOP, fill = BOTH, expand = 1)
My question is why does pcolormesh work in the second line above when I didn't import that command from matplotlib.pyplot? I'm new to Python, and I'm sure I'm missing something, but if I wanted to use the pcolormesh command in the past, I had to import it. Thanks.
Your function calls created objects and those objects have methods. You don't need to import those methods as they are attached directly to the object. They are different from importing a function as you don't have direct access to those methods: they can only be accessed from the object.
when you set fig = figure(), you created an object. If you print(repr(fig)) you'll see something like this.
'<matplotlib.figure.Figure object at 0x000000000784F208>'
so fig is a Figure object. This objects comes with some methods and properties attached to it. You can get a list of all the methods using dir(fig) (it's a long list, so I won't print it here).
fig.subplot(111) calls the subplot method attached to your fig object. It returns a new object (an AxesSubplot). That object has a method attached to it called pcolormesh. If you want to play around with that object, you can do this.
ax = fig.subplot(111)
ax.pcolormesh(X, Y, Z, cmap = get_cmap('BuPu'))
print(repr(ax))
In addition to doing your stuff, this will print <matplotlib.axes._subplots.AxesSubplot at 0x8996f28>.
I remember being similarly confused by matplot.pyplot when I first started out because you can often do nearly identical things with a function (matplotlib.pyplot.pcolomesh) and as a method of an object (in the above example, ax.pcolormesh). They mention it in the API explanation here and here.
I'm trying to create an animated histogram for work, using matplotlib.animation, but animation.FuncAnimation is not functioning properly : when using this code, that i found on the official documentation,
"""
A simple example of an animated plot
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
x = np.arange(0, 2*np.pi, 0.01)
line, = ax.plot(x, np.sin(x))
def animate(i):
print(i)
line.set_ydata(np.sin(x + i/10.0)) # update the data
return line,
# Init only required for blitting to give a clean slate.
def init():
line.set_ydata(np.ma.array(x, mask=True))
return line,
ani = animation.FuncAnimation(fig, animate, np.arange(1, 200),init_func=init,interval=25, blit=True)
plt.show()
I get as final result the graph created by init() function (an empty graph also), but no animate iterations. Furthermore, I tested other codes, which practically gave me the same result : i get the initialization, or the first frame, but not more. matplotlib and matplotlib.animation are installed, everything seems to be ok, except it doesn't work. Have someone an idea how to fix it ? (Thank you in advance :) !)
I had the same issue working with Jupyter notebook and I solved it by inserting the line
%matplotlib notebook
in the code.
It may be that IPython inside your Spyder is configured to automatically use the inline backend. This would show your plots inside the console as png images. Of course png images cannot be animated.
I would suggest not to use IPython but execute the script in a dedicated Python console. In Spyder, go to Run/Configure.. and set the option to new dedicated Python console.
I'm working with matplotlib plotting and use ioff() to switch interactive mode off to suppress the automatic opening of the plotting window on figrue creation. I want to have full control over the figure and only see it when explicitely using the show() command.
Now apparently the built-in commands to clear figures and axes do not work properly anymore.
Example:
import numpy as np
import matplotlib.pyplot as mpp
class PlotTest:
def __init__(self,nx=1,ny=1):
# Switch off interactive mode:
mpp.ioff()
# Create Figure and Axes:
self.createFigure(nx, ny)
def createFigure(self,nx=1,ny=1):
self.fig, self.axes = mpp.subplots(nx,ny)
if nx*ny == 1:
self.axes = np.array([self.axes])
def linePlot(self):
X = np.linspace(0,20,21)
Y = np.random.rand(21)
self.axes[0].plot(X,Y)
P = PlotTest()
P.linePlot()
P.fig.show()
Now I was thinking I could use P.fig.clear() any time to simply clear P.fig, but apparently that's not the case.
Writing P.fig.clear() directly into the script and execute it together it works and all I see is an empty figure. However that's rather pointless as I never get to see the actual plot like that.
Doing P.fig.clear() manually in the console does not do anything, regardless if the plot window is open or not, all other possible commands fail as well:
P.fig.clf()
P.axes[0].clear()
P.axes[0].cla()
mpp.clf()
mpp.cla()
mpp.close(P.fig)
Wrapping the command into a class method doesn't work either:
def clearFig(self):
self.fig.clear()
EDIT ================
After a clear() fig.axes is empty, yet show() still shows the old plot with the axes still being plotted.
/EDIT ================
Is it because I switched off interactive mode?
If you add a call to plt.draw() after P.fig.clear() it clears the figure. From the docs,
This is used in interactive mode to update a figure that has been altered, but not automatically re-drawn. This should be only rarely needed, but there may be ways to modify the state of a figure with out marking it as stale. Please report these cases as bugs.
I guess this is not a bug as you have switched off interactive mode so it is now your responsibility to explicitly redraw when you want to.
You can also use P.fig.canvas.draw_idle() which could be wrapper in the class as clearFigure method.