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.
Related
Updated MRE with subplots
I'm not sure of the usefulness of the original question and MRE. The margin padding seems to be properly adjusted for large x and y labels.
The issue is reproducible with subplots.
Using matplotlib 3.4.2
fig, axes = plt.subplots(ncols=2, nrows=2, figsize=(8, 6))
axes = axes.flatten()
for ax in axes:
ax.set_ylabel(r'$\ln\left(\frac{x_a-x_b}{x_a-x_c}\right)$')
ax.set_xlabel(r'$\ln\left(\frac{x_a-x_d}{x_a-x_e}\right)$')
plt.show()
Original
I am plotting a dataset using matplotlib where I have an xlabel that is quite "tall" (it's a formula rendered in TeX that contains a fraction and is therefore has the height equivalent of a couple of lines of text).
In any case, the bottom of the formula is always cut off when I draw the figures. Changing figure size doesn't seem to help this, and I haven't been able to figure out how to shift the x-axis "up" to make room for the xlabel. Something like that would be a reasonable temporary solution, but what would be nice would be to have a way to make matplotlib recognize automatically that the label is cut off and resize accordingly.
Here's an example of what I mean:
import matplotlib.pyplot as plt
plt.figure()
plt.ylabel(r'$\ln\left(\frac{x_a-x_b}{x_a-x_c}\right)$')
plt.xlabel(r'$\ln\left(\frac{x_a-x_d}{x_a-x_e}\right)$', fontsize=50)
plt.title('Example with matplotlib 3.4.2\nMRE no longer an issue')
plt.show()
The entire ylabel is visible, however, the xlabel is cut off at the bottom.
In the case this is a machine-specific problem, I am running this on OSX 10.6.8 with matplotlib 1.0.0
Use:
import matplotlib.pyplot as plt
plt.gcf().subplots_adjust(bottom=0.15)
# alternate option without .gcf
plt.subplots_adjust(bottom=0.15)
to make room for the label, where plt.gcf() means get the current figure. plt.gca(), which gets the current Axes, can also be used.
Edit:
Since I gave the answer, matplotlib has added the plt.tight_layout() function.
See matplotlib Tutorials: Tight Layout Guide
So I suggest using it:
fig, axes = plt.subplots(ncols=2, nrows=2, figsize=(8, 6))
axes = axes.flatten()
for ax in axes:
ax.set_ylabel(r'$\ln\left(\frac{x_a-x_b}{x_a-x_c}\right)$')
ax.set_xlabel(r'$\ln\left(\frac{x_a-x_d}{x_a-x_e}\right)$')
plt.tight_layout()
plt.show()
In case you want to store it to a file, you solve it using bbox_inches="tight" argument:
plt.savefig('myfile.png', bbox_inches="tight")
An easy option is to configure matplotlib to automatically adjust the plot size. It works perfectly for me and I'm not sure why it's not activated by default.
Method 1
Set this in your matplotlibrc file
figure.autolayout : True
See here for more information on customizing the matplotlibrc file: http://matplotlib.org/users/customizing.html
Method 2
Update the rcParams during runtime like this
from matplotlib import rcParams
rcParams.update({'figure.autolayout': True})
The advantage of using this approach is that your code will produce the same graphs on differently-configured machines.
plt.autoscale() worked for me.
You can also set custom padding as defaults in your $HOME/.matplotlib/matplotlib_rc as follows. In the example below I have modified both the bottom and left out-of-the-box padding:
# The figure subplot parameters. All dimensions are a fraction of the
# figure width or height
figure.subplot.left : 0.1 #left side of the subplots of the figure
#figure.subplot.right : 0.9
figure.subplot.bottom : 0.15
...
There is also a way to do this using the OOP interface, applying tight_layout directly to a figure:
fig, ax = plt.subplots()
fig.set_tight_layout(True)
https://matplotlib.org/stable/api/figure_api.html
for some reason sharex was set to True so I turned it back to False and it worked fine.
df.plot(........,sharex=False)
You need to use sizzors to modify the axis-range:
import sizzors as sizzors_module
sizzors_module.reshape_the_axis(plt).save("literlymylief.tiff")
I am using a function which spits out a figure object of validation data. My script calculates a few model parameters that I would like to plot on top of this existing figure object. How can I do this? Whenever I try to plot my modeled data, it does so in a new window. Here's what my code looks like:
datafig = plotting_function(args) #Returning a figure object
datafig.show()
plt.plot([modeled_x],[modeled_y]) #Plotting in a new window
I've tried using plt.hold() / plt.hold(True) but this doesn't do anything. Any ideas?
Edit:
MCVE:
import matplotlib.pyplot as plt
def fig_create():
fig_1, ax_1 = plt.subplots()
ax_1.plot([0,1],[0,1])
fig_2, ax_2 = plt.subplots()
ax_2.plot([0,1],[0,5])
return fig_1, ax_1, fig_2, ax_2
figure_1, axes_1, figure_2, axes_2 = fig_create()
plt.close("all") # Spyder plots even without a plt.show(), so running the function generates figures. I'm closing them here.
figure_2.show()
plt.figure(2)
plt.plot([0,1],[0,10])
Result of the MCVE: https://i.imgur.com/FiCJX33.png
You need to specify which axis to plot on. plt.figure(2) will make a figure with a number of 2, regardless of whether an existing figure has that number or not! axes_2.plot(), however will plot whatever data you input directly onto axes_2 and whatever was there already. If it doesn't immediately show up you should add plt.draw() after the plot function.
Try not to mix plt, notation and ax notation as this will create confusion later on! If you are using fig and ax, stick with those!
You can specify which figure to plot to by calling plt.figure(my_figure_index) before any plt.plot (or any other plt plotting function) call.
For example:
plt.figure(10) # creates new figure if doesn't exist yet
plt.plot(...) # plots in figure 10
plt.figure(2) # creates new figure if doesn't exist yet
plt.plot(...) # plots in this figure 2
plt.figure(10) # figure already exists, just makes it the active one
plt.plot(...) # plots in figure 10 (in addition to already existing stuff)
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.
Using Pandas to plot in I-Python Notebook, I have several plots and because Matplotlib decides the Y axis it is setting them differently and we need to compare that data using the same range.
I have tried several variants on: (I assume I'll need to apply the limits to each plot.. but since I can't get one working... From the Matplotlib doc it seems that I need to set ylim, but can't figure the syntax to do so.
df2250.plot(); plt.ylim((100000,500000)) <<<< if I insert the ; I get int not callable and if I leave it out I get invalid syntax. anyhow, neither is right...
df2260.plot()
df5.plot()
I'm guessing this was a feature added after this answer was accepted in 2013; DataFrame.plot() now exposes a ylim parameter that sets the y axis limits:
df.plot(ylim=(0,200))
See pandas documentation for details.
Pandas plot() returns the axes, you can use it to set the ylim on it.
ax1 = df2250.plot()
ax2 = df2260.plot()
ax3 = df5.plot()
ax1.set_ylim(100000,500000)
ax2.set_ylim(100000,500000)
etc...
You can also pass an axes to Pandas plot, so plotting it in the same axes can be done like:
ax1 = df2250.plot()
df2260.plot(ax=ax1)
etc...
If you want a lot of different plots, defining the axes beforehand and within one figure might be the solution that gives you the most control:
fig, axs = plt.subplots(1,3,figsize=(10,4), subplot_kw={'ylim': (100000,500000)})
df2260.plot(ax=axs[0])
df2260.plot(ax=axs[1])
etc...
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?