You turn on xkcd style by:
import matplotlib.pyplot as plt
plt.xkcd()
But how to disable it?
I try:
self.fig.clf()
But it won't work.
In a nutshell, either use the context manager as #Valentin mentioned, or call plt.rcdefaults() afterwards.
What's happening is that the rc parameters are being changed by plt.xkcd() (which is basically how it works).
plt.xkcd() saves the current rc params returns a context manager (so that you can use a with statement) that resets them at the end. If you didn't hold on to the context manager that plt.xkcd() returns, then you can't revert to the exact same rc params that you had before.
In other words, let's say you had done something like plt.rc('lines', linewidth=2, color='r') before calling plt.xkcd(). If you didn't do with plt.xkcd(): or manager = plt.xkcd(), then the state of rcParams after calling plt.rc will be lost.
However, you can revert back to the default rcParams by calling plt.rcdefaults(). You just won't retain any specific changes you made before calling plt.xkcd().
I see this in the doc, does it help?
with plt.xkcd():
# This figure will be in XKCD-style
fig1 = plt.figure()
# ...
# This figure will be in regular style
fig2 = plt.figure()
If not, you can look at matplotlib.pyplot.xkcd's code and see how they generate the context manager that allows reversing the config
You could try
manager = plt.xkcd()
# my xkcd plot here
mpl.rcParams.update(manager._rcparams)
this should reset the previous state, emulating the context manager. Obviously, it has not all the features for a context manager, e.g., the reset in case of exceptions, etc.
Or, w/o messing with the internals of the context manager
saved_state = mpl.rcParams.copy()
mpl.xkcd()
# my xkcd plot here
mpl.rcParams.update(saved_state)
Just use that
import matplotlib.pyplot as plt
plt.rcdefaults()
# before showing the plot
add this to the beginning of your code
import matplotlib as mpl
mpl.rcParams.update(mpl.rcParamsDefault)
you can simply use plt.rcdefaults or pyplot.rcdefaults before plt.show().
it will surely reset the rcparams to defaults.
I tried and it worked.
simply use ,
plt.xkcd(False)
that worked good for me
Related
I want to write a module with a function to set default style parameters from a matplotlibrc file. A minimal example of the module style.py:
import matplotlib as mpl
def set_default():
mpl.rc_file('./matplotlibrc')
If I want to use the module in a jupyter notebook with inline plotting, the inline plot is not shown, when I call style.set_default() before having plotted anything before.
So If I call
%matplotlib inline
style.set_default()
plt.plot()
the output is an empty list and no plot is shown. If I call e.g.
plt.plot()
after enabling inline plotting and before calling the set_default function, the output of both plot calls is shown inline.
This even happens, when the matplotlibrc file is empty as it is in my minimal example.
Does anyone understand why this happens and has an idea how to solve this problem or another way how to set a default style in a module using a matplotlibrc file?
Here are also two images of both cases in a jupyter notebook:
inline broken
inline working
Extra question: Why is the second plot in the second case larger, when the loaded matplotlibrc is empty?
Short version: Use mpl.style.use instead of mpl.rc_file.
Long version:
You may print out the backend in use to see what is going on.
import matplotlib as mpl
def set_default():
mpl.rc_file('matplotlibrc.txt') # this is an empty file
import matplotlib.pyplot as plt
print mpl.get_backend()
# This prints u'TkAgg' (in my case) the default backend in use
# due to my rc Params
%matplotlib inline
print mpl.get_backend()
# This prints "module://ipykernel.pylab.backend_inline", because inline has been set
set_default()
print mpl.get_backend()
# This prints "agg", because this is the default backend reset by setting the empty rc file
plt.plot()
# Here, no plot is shown because agg (a non interactive backend) is used.
Until here no supprise.
Now the second case.
import matplotlib as mpl
def set_default():
mpl.rc_file('matplotlibrc.txt') # this is an empty file
import matplotlib.pyplot as plt
print mpl.get_backend()
# This prints u'TkAgg' (in my case) the default backend in use, same as above
%matplotlib inline
print mpl.get_backend()
# This prints "module://ipykernel.pylab.backend_inline", because inline has been set
plt.plot()
# This shows the inline plot, because the inline backend is active.
set_default()
print mpl.get_backend()
# This prints "agg", because this is the default backend reset by setting the new empty rc file
plt.plot()
# Here comes the supprise: Although "agg" is the backend, still, an inline plot is shown.
# This is due to the inline backend being the one registered in pyplot
# when doing the first plot. It cannot be changed afterwards.
The main point is, you may still change the backend, until the first plot is produced, not after.
The same argument goes for the figure size. The default matplotlib figure size is (6.4,4.8), while the one being set with the inline backend is (6.0,4.0). Also the figure dpi is different, it is 100 in the default rcParams, but 72. in the inline configuration. This makes the plot appear much smaller.
Now to the actual problem. I suppose the use of a stylesheet is meant here to set some styles for plots, not to change the backend. Hence you would rather only set the style from the rc file. This can be done in the usual way,using matplotlib.style.use
def set_default():
mpl.style.use('matplotlibrc.txt')
When this is used, it will not overwrite the backend in use, but only update those parameters, specified in the file itself.
It seems that the standard way of creating a figure in matplotlib doesn't behave as I'd expect in python: by default calling fig = matplotlib.figure() in a loop will hold on to all the figures created, and eventually run out of memory.
There are quite a few posts which deal with workarounds, but requiring explicit calls to matplotlib.pyplot.close(fig) seems a bit hackish. What I'd like is a simple way to make fig reference counted, so I won't have to worry about memory leaks. Is there some way to do this?
If you create the figure without using plt.figure, then it should be reference counted as you expect. For example (This is using the non-interactive Agg backend, as well.)
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
# The pylab figure manager will be bypassed in this instance.
# This means that `fig` will be garbage collected as you'd expect.
fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111)
If you're only going to be saving figures rather than displaying them, you can use:
def savefig(*args, **kwargs):
plt.savefig(*args, **kwargs)
plt.close(plt.gcf())
This is arguably no less hacky, but whatever.
If you want to profit from the use of pyplot and have the possibility to wrap the figure in a class of your own, you can use the __del__ method of your class to close the figure.
Something like:
import matplotlib.pyplot as plt
class MyFigure:
"""This is my class that just wraps a matplotlib figure"""
def __init__(self):
# Get a new figure using pyplot
self.figure = plt.figure()
def __del__(self):
# This object is getting deleted, close its figure
plt.close(self.figure)
Whenever the garbage collector decides to delete your figure because it is inaccessible, the matplotlib figure will be closed.
However note that if someone has grabbed the figure (but not your wrapper) they might be annoyed that you closed it. It probably can be solved with some more thought or imposing some restrictions on usage.
How do pyplot functions such as show() and savefig() not require a "plot object" to work?
For example, the following code works, but somehow I expect to use a file handler or pass a "plot object" into plt.show() and plot.savefig("venn3.pdf").
from matplotlib import pyplot as plt
from matplotlib_venn import venn3, venn3_circles
# Subset sizes
s = (2,3,4,3,1,0.5,4)
v = venn3(subsets=s, set_labels=('A', 'B', 'C'))
# Subset labels
v.get_label_by_id('100').set_text('Abc')
v.get_label_by_id('010').set_text('aBc')
v.get_label_by_id('110').set_text('ABc')
v.get_label_by_id('001').set_text('Abc')
v.get_label_by_id('101').set_text('aBc')
v.get_label_by_id('011').set_text('ABc')
v.get_label_by_id('111').set_text('ABC')
# Subset colors
v.get_patch_by_id('100').set_color('c')
v.get_patch_by_id('010').set_color('#993333')
v.get_patch_by_id('110').set_color('blue')
# Subset alphas
v.get_patch_by_id('101').set_alpha(0.4)
v.get_patch_by_id('011').set_alpha(1.0)
v.get_patch_by_id('111').set_alpha(0.7)
# Border styles
c = venn3_circles(subsets=s, linestyle='solid')
c[0].set_ls('dotted') # Line style
c[1].set_ls('dashed')
c[2].set_lw(1.0) # Line width
plt.show() # For show() to work without using variable v seems counter-intuitive to me.
plt.savefig("venn3.pdf") # For savefig() to work without using variable v seems counter-intuitive to me.
2[]
matplotlib.pyplot is often called "statemachine". This means that the function it provides do certain things depending on the internal state of pyplot.
In your code, you have created a figure and this is stored as an object; pyplot knows it has one figure.
If you then call other commands, it is assumend that they apply to that one figure which has been created previously, like plt.savefig.
plt.show() would work on all previously created figures (all of them would be shown).
Pyplot uses a global variable to hold the figure object. All pyplot functions work with that variable(s). If you are working interactively, pyplot is perfectly fine since only you will modify that variable. If you are writing multi-threaded or multi-user code pyplot will not work, and you would have to use the layer benath it, which needs the figure object passed in (and is a terrible interface).
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.
Is there a way to close a pyplot figure in OS X using the keyboard (as far as I can see you can only close it by clicking the window close button)?
I tried many key combinations like command-Q, command-W, and similar, but none of them appear to work on my system.
I also tried this code posted here:
#!/usr/bin/env python
import matplotlib.pyplot as plt
plt.plot(range(10))
def quit_figure(event):
if event.key == 'q':
plt.close(event.canvas.figure)
cid = plt.gcf().canvas.mpl_connect('key_press_event', quit_figure)
plt.show()
However, the above doesn't work on OS X either. I tried adding print statements to quit_figure, but it seems like it's never called.
I'm trying this on the latest public OS X, matplotlib version 1.1.1, and the standard Python that comes with OS X (2.7.3). Any ideas on how to fix this? It's very annoying to have to reach for the mouse every time.
This is definitely a bug in the default OS X backend used by pyplot. Adding the following two lines at the top of the file switches to a different backend that works for me, if this helps anyone else.
import matplotlib
matplotlib.use('TKAgg')
I got around this by replacing
plt.show()
with
plt.show(block=False)
input("Hit Enter To Close")
plt.close()
A hack at its best, but I hope that helps someone
use interactive mode:
import matplotlib.pyplot as plt
# Enable interactive mode:
plt.ion()
# Make your plot: No need to call plt.show() in interactive mode
plt.plot(range(10))
# Close the active plot:
plt.close()
# Plots can also be closed via plt.close('all') to close all open plots or
# plt.close(figure_name) for named figures.
Checkout the "What is interactive mode?" section in this documentation
Interactive mode can be turned off at any point with plt.ioff()
When you have focus in the matplotlib window, the official keyboard shortcut is ctrl-W by this:
http://matplotlib.org/1.2.1/users/navigation_toolbar.html
As this is a very un-Mac way to do things, it is actually cmd-W. Not so easy to guess, is it?
If you are using an interactive shell, you can also close the window programmatically. See:
When to use cla(), clf() or close() for clearing a plot in matplotlib?
So, if you use pylab or equivalent (everything in the same namespace), it is just close(fig). If you are loading the libraries manually, you need to take close from the right namespace, for example:
import matplotlib.pyplot as plt
fig = plt.figure()
plt.plot([0,1,2],[0,1,0],'r')
fig.show()
plt.close(fig)
The only catch here is that there is no such thing as fig.close even though one would expect. On the other hand, you can use plt.close('all') to regain your desktop.