Reverse y-axis and Draw w.r.t it in matplotlib? - python

This answer has beautifully showed how to reverse the y-axis. However, I now wish to draw all my dots, etc. with respect to this reversed version of coordinate system.
I find the following all fail this purpose:
plt.figure()
plt.gca().invert_yaxis()
plt.plot([1,2],[1,3]) # just a random line
plt.figure()
plt.plot([1,2],[1,3]) # just a random line
plt.gca().invert_yaxis()
How may I fix it and let it work?
For me, if I use an OOP-style figure, i.e.
fig = plt.figure()
axes = fig.add_axes([0.1, 0.1, 0.8, 0.8])
axes.plot([1,2],[1,3]) # just a random line
axes.invert_yaxis()
it works.
But for the current two non-OOP styles listed above, a new figure with a reversed y-axis is created, but the line is not there.

I still can't reproduce your original error using the snippet you posted (is that really all of your code?), but what you're describing sounds like it could be caused by a race condition when you call plt.gca() twice in quick succession. You could perhaps try inserting a short pause between plotting your two figures:
import time
plt.figure()
plt.gca().invert_yaxis()
plt.plot([1,2],[1,3]) # just a random line
time.sleep(0.1)
plt.figure()
plt.plot([1,2],[1,3]) # just a random line
plt.gca().invert_yaxis()
However, as a more general point I would strongly recommend that you avoid using gca() and gcf() except for convenience during interactive sessions - it's much more Pythonic to pass the axes or figure objects explicitly, and it makes it way easier to keep track of exactly which axes/figures are being modified.

Related

Python 3 Adding a Colorbar with Matplotlib

I've done a fair amount of research on adding a colorbar to a plot but I'm still really confused about how to add one. The examples I've seen use different ways of doing so, which just confuses me because I don't get what the "right" way is.
I've seen there is a colorbar method and a colorbar() function, so what should one use to simply add a colorbar?
Some examples do this:
fig,ax = plt.subplots()
s = ax.scatter(x,y,cmap = coolwarm)
matplotlib.colorbar.ColorbarBase(ax=ax, cmap=coolwarm, values=sorted(v),
orientation="horizontal")
While some others simply call the function:
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
image = np.random.poisson(10., (100, 80))
i = ax.imshow(image, interpolation='nearest')
fig.colorbar(i)
I'm probably missing something here, but I just don't see how these both create a colorbar (I just copied the code for the colorbar and excluded that of the data).
My question is simply: what is the simplest way to add a colorbar to a plot?
Thanks!
The first example you quote creates an instance of ColorbarBase. This is usually not the recommended way; there might be some exceptions, but in general there is absolutely no reason to use this.
The second example you quote is one or even the way to create a colorbar inside a figure. Using this, you are on the save side. Using the colorbar method of the figure instance makes it clear in which figure to place the colorbar and supplying the respective ScalarMappable (in this case an AxesImage) ensures that the colorbar uses the correct colors from that ScalarMappable.
fig, ax = plt.subplots()
im = ax.imshow(image)
fig.colorbar(im)
or
fig, ax = plt.subplots()
sc = ax.scatter(x,y, c=something)
fig.colorbar(sc)
There is an even easier method, which would be to simply call
plt.colorbar()
Note however that this may lead to confusions as it tries to automatically determine the plot for which the colorbar should be created. Thus, there is some chance that it fails and I would not recommend using it.

Python matplotlib error: "maximum recursion depth exceeded"

I am using Python and the matplotlib library.
I run through a very long code creating multiple figures along the way.
I do something like this, many many times:
plt.figure()
plt.plot(x, y)
plt.grid('on')
plt.close()
Then, at some point, I get the error:
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.
The error is clear to me, but: I do call "plt.close()".
Now that I am writing this I am realizing that maybe plt.close() has to take a specific qualifier for what figure to close? Like plt.close(1) etc. I guess I can use plt.close('all'), but what if I just want to close the most recent figure?
The code from the question should work fine. Since you close the figure in every loop step, there will only ever be one single figure open.
Minimal example, which does not produce any error:
import matplotlib.pyplot as plt
for i in range(30):
plt.figure()
plt.plot(range(i+3), range(i+3))
plt.grid('on')
plt.close()
plt.show() # doesn't show anything since no figure is open
So the reason for the error must be somewhere else in the code.
You should operate on matplotlib objects directly. It's so much less ambiguous:
fig, ax = plt.subplots()
ax.plot(x, y)
...
plt.close(fig)

draw order of grid lines and data in pyplot [duplicate]

This question already has answers here:
Matplotlib: draw grid lines behind other graph elements
(7 answers)
Closed 7 years ago.
I've got a library function which plots data into a pyplot figure containing several subplots.
I just added grid lines to all of the subplots but they overlay the actual data but I would prefer them to be in the background.
I've tried changing the order in which the plotting and ax.plot() ax.grid() commands are executed but that has no influence.
Is there a way to force the grid into the background?
Related bonus question: I'm also using axhline to designate the x=0 line but it always assumes the grid colour even though it is being specified in a different one ...
The way the code currently works:
def plot_the_things(fig=None):
# in case no figure is provided, make a new one,
# otherwise add to the existing one
plot_fig=fig if fig else plt.figure()
#[...some calculations of data ...]
plot_ax1 = plot_fig.add_subplot(3,3,1)
plot_ax1.axhline(y=0, ls='-', color='0.5')
plot_ax1.plot(self.diff_3[:,0],self.diff_3[:,1])
# [...setting labels, adapt axes limits in case the new data needs wider ones..]
plot_ax1.grid(b=True, which='major', axis='both', c='0.75', ls='-', linewidth=1)
# this is repeated in similar fashion for the other axes -- there are 9 of
# them, each plotting something different in a different axes
This function is called several times over. More precisely: It's actually part of a class. I have multiple instances of this class and call all of them, passing in the same figure object. Each instance then draws its own data, which works fine, and even the axhline() was shown properly (below the data!) but after I put in the command to add the grid, it always shows up on top of the data and covers the axhline, which is annoying.
... any way to fix this?
(I think I could and maybe should also move all the things that only need to run once to a place where they aren't repeatedly executed but time and mental resources are scant right now, so I went with the quickest way that worked... but I wouldn't expect this to change anything)
Use the zorder kwarg to your plot and axhline calls. The grid is plotted at zorder=2.5, so place the axhline and plot above this:
plot_ax1.axhline(y=0, ls='-', color='0.5', zorder=3)
plot_ax1.plot(self.diff_3[:,0],self.diff_3[:,1], zorder=4)
plot_ax1.grid(b=True, which='major', axis='both', c='0.75', ls='-', linewidth=1)
More info: here, and here.

How can I get matplotlib to show full subplots in an animation?

I'm trying to write a simple immune system simulator. I'm modeling infected tissue as a simple grid of cells and various intracellular signals, and I'd like to animate movement of cells in one plot and the intensity of viral presence in another as the infection progresses. I'm doing so with the matshow function provided by matplotlib. However, when I plot the two next to each other, the full grid gets clipped unless I stretch out the window myself. I can't address the problem at all when saving to an mp4.
Here's the default view, which is identical to what I observe when saving to mp4:
And here's what it looks like after stretching out the viewer window
I'm running Python 2.7.9 with matplotlib 1.4.2 on OS X 10.10.2, using ffmpeg 2.5.2 (installed via Homebrew). Below is the code I'm using to generate the animation. I tried using plt.tight_layout() but it didn't affect the problem. If anyone has any advice as to how to solve this, I'd really appreciate it! I'd especially like to be able to save it without viewing with plt.show(). Thanks!
def animate(self, fname=None, frames=100):
fig, (agent_ax, signal_ax) = plt.subplots(1, 2, sharey=True)
agent_ax.set_ylim(0, self.grid.shape[0])
agent_ax.set_xlim(0, self.grid.shape[1])
signal_ax.set_ylim(0, self.grid.shape[0])
signal_ax.set_xlim(0, self.grid.shape[1])
agent_mat = agent_ax.matshow(self.display_grid(),
vmin=0, vmax=10)
signal_mat = signal_ax.matshow(self.signal_display(virus),
vmin=0, vmax=20)
fig.colorbar(signal_mat)
def anim_update(tick):
self.update()
self.diffuse()
agent_mat.set_data(self.display_grid())
signal_mat.set_data(self.signal_display(virus))
return agent_mat, signal_mat
anim = animation.FuncAnimation(fig, anim_update, frames=frames,
interval=3000, blit=False)
if fname:
anim.save(fname, fps=5, extra_args=['-vcodec', 'libx264'])
else:
plt.show()
According to the matplotlib documentation
Because of how matshow() tries to set the figure aspect ratio to be the one of the array, if you provide the number of an already existing figure, strange things may happen.
I think you're better off using imshow instead (which I believe is what matshow calls. That has an aspect keyword argument which you could use if it doesn't work automatically.
Also according to the matplotlib documentation,
Sets origin to ‘upper’, ‘interpolation’ to ‘nearest’ and ‘aspect’ to equal.
I think you want to do the first two, but leave aspect as auto.
Well, one simple solution would be to just specify the width of the figure when creating it:
fig, (agent_ax, signal_ax) = plt.subplots(1, 2, sharey=True,
figsize=(16,6))

When to use cla(), clf() or close() for clearing a plot in matplotlib?

Matplotlib offers these functions:
cla() # Clear axis
clf() # Clear figure
close() # Close a figure window
When should I use each function and what exactly does it do?
They all do different things, since matplotlib uses a hierarchical order in which a figure window contains a figure which may consist of many axes. Additionally, there are functions from the pyplot interface and there are methods on the Figure class. I will discuss both cases below.
pyplot interface
pyplot is a module that collects a couple of functions that allow matplotlib to be used in a functional manner. I here assume that pyplot has been imported as import matplotlib.pyplot as plt.
In this case, there are three different commands that remove stuff:
See matplotlib.pyplot Functions:
plt.cla() clears an axis, i.e. the currently active axis in the current figure. It leaves the other axes untouched.
plt.clf() clears the entire current figure with all its axes, but leaves the window opened, such that it may be reused for other plots.
plt.close() closes a window, which will be the current window, if not specified otherwise.
Which functions suits you best depends thus on your use-case.
The close() function furthermore allows one to specify which window should be closed. The argument can either be a number or name given to a window when it was created using figure(number_or_name) or it can be a figure instance fig obtained, i.e., usingfig = figure(). If no argument is given to close(), the currently active window will be closed. Furthermore, there is the syntax close('all'), which closes all figures.
methods of the Figure class
Additionally, the Figure class provides methods for clearing figures.
I'll assume in the following that fig is an instance of a Figure:
fig.clf() clears the entire figure. This call is equivalent to plt.clf() only if fig is the current figure.
fig.clear() is a synonym for fig.clf()
Note that even del fig will not close the associated figure window. As far as I know the only way to close a figure window is using plt.close(fig) as described above.
There is just a caveat that I discovered today.
If you have a function that is calling a plot a lot of times you better use plt.close(fig) instead of fig.clf() somehow the first does not accumulate in memory. In short if memory is a concern use plt.close(fig) (Although it seems that there are better ways, go to the end of this comment for relevant links).
So the the following script will produce an empty list:
for i in range(5):
fig = plot_figure()
plt.close(fig)
# This returns a list with all figure numbers available
print(plt.get_fignums())
Whereas this one will produce a list with five figures on it.
for i in range(5):
fig = plot_figure()
fig.clf()
# This returns a list with all figure numbers available
print(plt.get_fignums())
From the documentation above is not clear to me what is the difference between closing a figure and closing a window. Maybe that will clarify.
If you want to try a complete script there you have:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(1000)
y = np.sin(x)
for i in range(5):
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, y)
plt.close(fig)
print(plt.get_fignums())
for i in range(5):
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, y)
fig.clf()
print(plt.get_fignums())
If memory is a concern somebody already posted a work-around in SO see:
Create a figure that is reference counted
plt.cla() means clear current axis
plt.clf() means clear current figure
also, there's plt.gca() (get current axis) and plt.gcf() (get current figure)
Read more here: Matplotlib, Pyplot, Pylab etc: What's the difference between these and when to use each?

Categories

Resources