How can I prevent a specific plot to be shown in Jupyter notebook? I have several plots in a notebook but I want a subset of them to be saved to a file and not shown on the notebook as this slows considerably.
A minimal working example for a Jupyter notebook is:
%matplotlib inline
from numpy.random import randn
from matplotlib.pyplot import plot, figure
a=randn(3)
b=randn(3)
for i in range(10):
fig=figure()
plot(b)
fname='s%03d.png'%i
fig.savefig(fname)
if(i%5==0):
figure()
plot(a)
As you can see I have two types of plots, a and b. I want a's to be plotted and shown and I don't want the b plots to be shown, I just want them them to be saved in a file. Hopefully this will speed things a bit and won't pollute my notebook with figures I don't need to see.
Thank you for your time
Perhaps just clear the axis, for example:
fig= plt.figure()
plt.plot(range(10))
fig.savefig("save_file_name.pdf")
plt.close()
will not plot the output in inline mode. I can't work out if is really clearing the data though.
I was able to prevent my figures from displaying by turning interactive mode off using the function
plt.ioff()
To prevent any output from a jupyter notebook cell you may start the cell with
%%capture
This might be usefull in cases all other methods shown here fail.
From IPython 6.0 on, there is another option to turn the inline output off (temporarily or persistently). This has been introduced in this pull request.
You would use the "agg" backend to not show any inline output.
%matplotlib agg
It seems though that if you had activated the inline backend first, this needs to be called twice to take effect.
%matplotlib agg
%matplotlib agg
Here is how it would look in action
I'm a beginner though,off the inline mode when you don't want to see the output in your notebook by:
%matplotlib auto
or:
%matplotlib
to use it back:
%matplotlib inline
more better solution would be to use:
plt.ioff()
which says inline mode off.
hope it helps.
On Jupyter 6.0, I use the following snippet to selectively not display the matplot lib figures.
import matplotlib as mpl
...
backend_ = mpl.get_backend()
mpl.use("Agg") # Prevent showing stuff
# Your code
mpl.use(backend_) # Reset backend
Building off #importanceofbeingernest's answer, one may call some function in a loop, and at each iteration, want to render a plot. However, between the each plot, you may want to render additional stuff.
Concretely:
Iterate a list of IDs
Call a function so a plot is rendered for each "ID"
Between each plot, render some markdown
# <cell begins>
def render(id):
fig, axes = plt.subplots(2, 1)
plt.suptitle(f'Metrics for {id}')
df.ColA.plot.bar(ax=axes[0])
df.ColB.plot.bar(ax=axes[1])
return fig
# <cell ends>
# -------------------------------------
# <cell begins>
%matplotlib agg
for id in df.ID.value_counts().index:
fig = render(id)
display(fig)
display(Markdown('---'))
# <cell ends>
Related
I wish to have an interactive map that you can click where, once clicked, a SkewT and Hodograph will be plotted showing the information for that location. I have thus created a class where I add all the necessary informations using the metpy library and I am able to successfully create these graphs:
SkewT and Hodograph plotted
The problem comes when I'm trying to import the classes I've created to generate these plots into jupyterlab. Since the code to actually make these plots is quite cumbersome, I'd rather
keep the code in a separate file and import my SoundingGraphs class, but it's not working. The graphs never get plotted inside a cell, they instead appear in the logs as a Warning and as an Info and I have no idea why:
Graphs appearing inside logs
Tried to use plt.show() inside my file, tried returning plt to then use plt.show() inside a cell of the notebook, tried using %matplotlib widget, %matplotlib notebook and %matplotlib inline, tried changing jupyterlab versions, none of these changed anything.
I have found one solution that I disliked, but that does work, which is rather than doing a plt.show(), to instead do this inside my class:
buffer = BytesIO()
plt.savefig(buffer, format='png')
return buffer
And in the notebook I would do:
image = Image()
display(image)
def on_generate_button_clicked(b):
buffer = SoundingGraphs(infos)
buffer.seek(0)
image.value=buffer.read()
image.format='png'
generate_button.on_click(on_generate_button_clicked)
I don't quite like this approach because further down the line I would like to add interactivity to my plots, like show values of plot when hovered and things like that, thus I don't just want to show an image. So I'd like to know if it is indeed possible to plt.show() a plot created inside another file in a cell.
Using:
Python 3.6.9
jupyterlab==3.2.9
jupyterlab-pygments==0.1.2
jupyterlab-server==2.10.3
jupyterlab-widgets==1.1.0
ipykernel==5.5.6
ipyleaflet==0.14.0
ipympl==0.8.8
ipython==7.16.3
ipython-genutils==0.2.0
ipywidgets==7.7.0
matplotlib==3.3.4
Thanks!
Yes, it is possible after all!
%matplotlib widget needs to be used at the start of the notebook and since the class method will be called from another function (on a button.on_click event), it is possible to use the #out.capture() decorator above it so that the plt.show() gets displayed. It's also possible to make the figure a class attribute to be able to have more control.
So here's a bit of working code if someone would like to replicate:
Notebook
%matplotlib widget
from ipywidgets import Button, Output
from myfile import MyClass
out = Output()
example_button = Button(
description='Example',
disabled=False,
button_style='',
tooltip='Click me'
)
#out.capture()
def on_example_button_clicked(b):
example_button.disabled = True
myclass = MyClass()
myclass.create_plot()
out.clear_output(wait=True)
display(myclass.fig.canvas)
example_button.disabled = False
example_button.on_click(on_example_button_clicked)
display(example_button)
display(out)
myfile.py
import matplotlib.pyplot as plt
class MyClass():
def __init__(self):
plt.ioff() # otherwise it'll also show inside logs
plt.clf()
self.fig = plt.figure()
def create_plot(self):
plt.plot([1, 2, 3, 4])
plt.ylabel('some numbers')
I create some plots in one run of code, the plots are in plots tab. I tried to delete it all each time i rerun it but somehow the previous plots are still there not closing, it only creates new plots without clearing the previous plots from the previous run. I already tried to use plt.close('all') but it does not work. How do i clear all plots every time i rerun the code?
Here's my code
import pandas as pd
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
plt.close('all')
avo_sales = pd.read_csv('avocados.csv')
avo_sales.rename(columns = {'4046':'small Hass sold','4225':'large Hass sold','4770':'xlarge Hass sold'},
inplace= True)
for column in avo_sales.columns[2:11]:
sns.set()
fig, ax = plt.subplots()
sns.set(style="ticks")
sns.boxplot(column, data= avo_sales) # column is chosen here
sns.despine(offset=10, trim=True)
The images in the plots pane are handled by Spyder and are not reachable from the IPython console.
A simple solution would be to press the "remove images" icon before you re-run the code:
I don't know how to even get Spyder to put plots in the plot pane, but here's a few things that might work.
Try disabling some of the pane options:
Try some magic functions:
%reset - reset everything
%matplotlib - puts all plots inline with your code in the interactive window
%clear - clears the interactive window
Use IPython directly to help (via: https://gist.github.com/stsievert/8655158355b7155b2dd8):
from IPython import get_ipython
get_ipython().magic('reset -sf')
I generate a lots of figures with a script which I do not display but store to harddrive. After a while I get the message
/usr/lib/pymodules/python2.7/matplotlib/pyplot.py:412: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (matplotlib.pyplot.figure) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam figure.max_num_figures).
max_open_warning, RuntimeWarning)
Thus, I tried to close or clear the figures after storing. So far, I tried all of the followings but no one works. I still get the message from above.
plt.figure().clf()
plt.figure().clear()
plt.clf()
plt.close()
plt.close('all')
plt.close(plt.figure())
And furthermore I tried to restrict the number of open figures by
plt.rcParams.update({'figure.max_num_figures':1})
Here follows a piece of sample code that behaves like described above. I added the different options I tried as comments at the places I tried them.
from pandas import DataFrame
from numpy import random
df = DataFrame(random.randint(0,10,40))
import matplotlib.pyplot as plt
plt.ioff()
#plt.rcParams.update({'figure.max_num_figures':1})
for i in range(0,30):
fig, ax = plt.subplots()
ax.hist([df])
plt.savefig("/home/userXYZ/Development/pic_test.png")
#plt.figure().clf()
#plt.figure().clear()
#plt.clf()
#plt.close() # results in an error
#plt.close('all') # also error
#plt.close(plt.figure()) # also error
To be complete, that is the error I get when using plt.close:
can't invoke "event" command: application has been destroyed
while executing "event generate $w <>"
(procedure "ttk::ThemeChanged" line 6)
invoked from within "ttk::ThemeChanged"
The correct way to close your figures would be to use plt.close(fig), as can be seen in the below edit of the code you originally posted.
from pandas import DataFrame
from numpy import random
df = DataFrame(random.randint(0,10,40))
import matplotlib.pyplot as plt
plt.ioff()
for i in range(0,30):
fig, ax = plt.subplots()
ax.hist(df)
name = 'fig'+str(i)+'.png' # Note that the name should change dynamically
plt.savefig(name)
plt.close(fig) # <-- use this line
The error that you describe at the end of your question suggests to me that your problem is not with matplotlib, but rather with another part of your code (such as ttk).
plt.show() is a blocking function, so in the above code, plt.close() will not execute until the fig windows are closed.
You can use plt.ion() at the beginning of your code to make it non-blocking. Even though this has some other implications the fig will be closed.
I was still having the same issue on Python 3.9.7, matplotlib 3.5.1, and VS Code (the issue that no combination of plt.close() closes the figure). I have three loops which the most inner loop plots more than 20 figures. The solution that is working for me is using agg as backend and del someFig after plt.close(someFig). Subsequently, the order of code would be something like:
import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt
someFig = plt.figure()
.
.
.
someFig.savefig('OUTPUT_PATH')
plt.close(someFig) # --> (Note 1)
del someFig
.
.
.
NOTE 1: If this line is removed, the output figures may not be plotted correctly! Especially when the number of elements to be rendered in the figure is high.
NOTE 2: I don't know whether this solution could backfire or not, but at least it is working and not hugging RAM or preventing plotting figures!
import tensorflow as tf
from matplotlib import pyplot as plt
sample_image = tf.io.read_file(str(PATH / 'Path to your file'))
sample_image = tf.io.decode_jpeg(sample_image)
print(sample_image.shape)
plt.figure("1 - Sample Image ")
plt.title(label="Sample Image", fontsize=12, color="red")
plt.imshow(sample_image)
plt.show(block=False)
plt.pause(3)
plt.close()
plt.show(block=False)
plt.pause(interval) do the trick
This does not really solve my problem, but it is a work-around to handle the high memory consumption I faced and I do not get any of the error messages as before:
from pandas import DataFrame
from numpy import random
df = DataFrame(random.randint(0,10,40))
import matplotlib.pyplot as plt
plt.ioff()
for i in range(0,30):
plt.close('all')
fig, ax = plt.subplots()
ax.hist([df])
plt.savefig("/home/userXYZ/Development/pic_test.png")
if I work on a matplotlib inline plot in an ipython notebook like this:
figure = plt.figure()
ax = figure.gca(projection="3d")
graph = np.empty([len(thetaYield),3])
for g, tY in zip(graph, thetaYield):
sample = HWtoPS(xiYield, rhoYield, tY)
g[...] = sample[:]
ax.plot(graph[:,0],graph[:,1], graph[:,2])
plt.show()
the plot is drawn inline in my notebook as it intended.
Now I want to add to add some data to this plot:
principalStress, vectors = eig(sigma)
ax.scatter(principalStress[0], principalStress[1], principalStress[2])
plt.show()
no error, but also no plot is drawn.
I expected to get an "updated" version of my plot with the additional data.
How can this be done?
A: This can be done at a cost of changed matplotlib Renderer
Currently, this cannot be done for the IPython "inline" graphs, however, if you opt to change a Renderer part of the matplotlib framework, to another one, the limitation of a singleton call of the .show() method does not hurt and you can ex post modify the object's content and it gets re-processed by the Renderer.
Simply:
add a directive ( IPython magic) %matplotlib qt
&
use additional matplotlib calls as you expect 'em to modify/update the figure object
( I love using this both during prototyping phases & for interactive 3D-viewing of complex data visualisations (which I heavily miss in notebook's "inline"s) )
BTW: do you have about any methodology, which would allow to store a matplotlib 3D-view plot, as a complete, state-full container, that can be sent to some other user for her/his "load" and UI-interactive review? Would be great to hear about any such working :o)
I am using iPython notebook wo do some visualization. Figures are inline (the profile defaults to interactive, as this supports a number of users who prefer interactive more frequently):
%pylab inline
Using the inline plot, I often set the fig size manually:
figsize(10,5)
I find that I need to run cells twice to realize a change in the fig size. For example, if I define cell [1] as figsize(10,5) and run it, the output is the correct size. If I then run cell [2] with `fig size(5,10)1 I get output that is of size (10,5). A second run of cell [2] draws correctly.
Any insight into why this is occurring? Is it due to the inline backend and I just need to live with it?
Thanks.
Definition: figsize(sizex, sizey)
Docstring:
Set the default figure size to be [sizex, sizey].
This is just an easy to remember, convenience wrapper that sets::
matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
This seem correct to me, if you run the following, whatever value of X, Y I always get the right plot
figsize(10,5)
plot(range(10))
if you run it after your plot, then you set the default for next plot... but without exact example, hard to say..