Probably this is a nice way to set up for example xmin and ymax only, etc.
回答 5
要添加到@Hima的答案中,如果要修改当前的x或y限制,可以使用以下内容。
import numpy as np # you probably alredy do this so no extra overhead
fig, axes = plt.subplot()
axes.plot(data[:,0], data[:,1])
xlim = axes.get_xlim()# example of how to zoomout by a factor of 0.1
factor =0.1
new_xlim =(xlim[0]+ xlim[1])/2+ np.array((-0.5,0.5))*(xlim[1]- xlim[0])*(1+ factor)
axes.set_xlim(new_xlim)
To add to @Hima’s answer, if you want to modify a current x or y limit you could use the following.
import numpy as np # you probably alredy do this so no extra overhead
fig, axes = plt.subplot()
axes.plot(data[:,0], data[:,1])
xlim = axes.get_xlim()
# example of how to zoomout by a factor of 0.1
factor = 0.1
new_xlim = (xlim[0] + xlim[1])/2 + np.array((-0.5, 0.5)) * (xlim[1] - xlim[0]) * (1 + factor)
axes.set_xlim(new_xlim)
I find this particularly useful when I want to zoom out or zoom in just a little from the default plot settings.
This should work. Your code works for me, like for Tamás and Manoj Govindan. It looks like you could try to update Matplotlib. If you can’t update Matplotlib (for instance if you have insufficient administrative rights), maybe using a different backend with matplotlib.use() could help.
回答 7
仅用于微调。如果只想设置轴的一个边界,而另一个边界不变,则可以选择以下一个或多个语句
plt.xlim(right=xmax)#xmax is your value
plt.xlim(left=xmin)#xmin is your value
plt.ylim(top=ymax)#ymax is your value
plt.ylim(bottom=ymin)#ymin is your value
Just for fine tuning. If you want to set only one of the boundaries of the axis and let the other boundary unchanged, you can choose one or more of the following statements
plt.xlim(right=xmax) #xmax is your value
plt.xlim(left=xmin) #xmin is your value
plt.ylim(top=ymax) #ymax is your value
plt.ylim(bottom=ymin) #ymin is your value
Take a look at the documentation for xlim and for ylim
If an axes (generated by code below the code shown in the question) is sharing the range with the first axes, make sure that you set the range after the last plot of that axes.
c.IPKernelApp.matplotlib=<CaselessStrEnum>Default:NoneChoices:['auto','gtk','gtk3','inline','nbagg','notebook','osx','qt','qt4','qt5','tk','wx']Configure matplotlib for interactive use with the default matplotlib backend.
I have to agree with foobarbecue (I don’t have enough recs to be able to simply insert a comment under his post):
It’s now recommended that python notebook isn’t started wit the argument --pylab, and according to Fernando Perez (creator of ipythonnb) %matplotlib inline should be the initial notebook command.
However, by leaving the () off the end of the plot type you receive a somewhat ambiguous non-error.
Erronious code:
df_randNumbers1.ix[:,["A","B"]].plot.kde
Example error:
<bound method FramePlotMethods.kde of <pandas.tools.plotting.FramePlotMethods object at 0x000001DDAF029588>>
Other than this one line message, there is no stack trace or other obvious reason to think you made a syntax error. The plot doesn’t print.
回答 9
在Jupyter的单独单元中运行绘图命令时,我遇到了同样的问题:
In[1]:%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
In[2]: x = np.array([1,3,4])
y = np.array([1,5,3])In[3]: fig = plt.figure()<Figure size 432x288with0Axes>#this might be the problemIn[4]: ax = fig.add_subplot(1,1,1)In[5]: ax.scatter(x, y)Out[5]:<matplotlib.collections.PathCollection at 0x12341234># CAN'T SEE ANY PLOT :(In[6]: plt.show()# STILL CAN'T SEE IT :(
通过将绘图命令合并到单个单元格中解决了该问题:
In[1]:%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
In[2]: x = np.array([1,3,4])
y = np.array([1,5,3])In[3]: fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(x, y)Out[3]:<matplotlib.collections.PathCollection at 0x12341234># AND HERE APPEARS THE PLOT AS DESIRED :)
I had the same problem when I was running the plotting commands in separate cells in Jupyter:
In [1]: %matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
In [2]: x = np.array([1, 3, 4])
y = np.array([1, 5, 3])
In [3]: fig = plt.figure()
<Figure size 432x288 with 0 Axes> #this might be the problem
In [4]: ax = fig.add_subplot(1, 1, 1)
In [5]: ax.scatter(x, y)
Out[5]: <matplotlib.collections.PathCollection at 0x12341234> # CAN'T SEE ANY PLOT :(
In [6]: plt.show() # STILL CAN'T SEE IT :(
The problem was solved by merging the plotting commands into a single cell:
In [1]: %matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
In [2]: x = np.array([1, 3, 4])
y = np.array([1, 5, 3])
In [3]: fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.scatter(x, y)
Out[3]: <matplotlib.collections.PathCollection at 0x12341234>
# AND HERE APPEARS THE PLOT AS DESIRED :)
Deprecation note:
As per the official Matplotlib guide, usage of the pylab module is no longer recommended. Please consider using the matplotlib.pyplot module instead, as described by this other answer.
The following seems to work:
from pylab import rcParams
rcParams['figure.figsize'] = 5, 10
This makes the figure’s width 5 inches, and its height 10 inches.
The Figure class then uses this as the default value for one of its arguments.
There is also this workaround in case you want to change the size without using the figure environment. So in case you are using plt.plot() for example, you can set a tuple with width and height.
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (20,3)
This is very useful when you plot inline (e.g. with IPython Notebook). As @asamaier noticed is preferable to not put this statement in the same cell of the imports statements.
Conversion to cm
The figsize tuple accepts inches so if you want to set it in centimetres you have to divide them by 2.54 have a look to this question.
回答 4
请尝试以下简单代码:
from matplotlib import pyplot as plt
plt.figure(figsize=(1,1))
x =[1,2,3]
plt.plot(x, x)
plt.show()
#!/usr/bin/env python"""
This is a small demo file that helps teach how to adjust figure sizes
for matplotlib
"""import matplotlib
print"using MPL version:", matplotlib.__version__
matplotlib.use("WXAgg")# do this before pylab so you don'tget the default back end.import pylab
import numpy as np
# Generate and plot some simple data:
x = np.arange(0,2*np.pi,0.1)
y = np.sin(x)
pylab.plot(x,y)
F = pylab.gcf()# Now check everything with the defaults:
DPI = F.get_dpi()print"DPI:", DPI
DefaultSize= F.get_size_inches()print"Default size in Inches",DefaultSizeprint"Which should result in a %i x %i Image"%(DPI*DefaultSize[0], DPI*DefaultSize[1])# the default is 100dpi for savefig:
F.savefig("test1.png")# this gives me a 797 x 566 pixel image, which is about 100 DPI# Now make the image twice as big, while keeping the fonts and all the# same size
F.set_size_inches((DefaultSize[0]*2,DefaultSize[1]*2))Size= F.get_size_inches()print"Size in Inches",Size
F.savefig("test2.png")# this results in a 1595x1132 image# Now make the image twice as big, making all the fonts and lines# bigger too.
F.set_size_inches(DefaultSize)# resetthe size
Size= F.get_size_inches()print"Size in Inches",Size
F.savefig("test3.png", dpi =(200))# change the dpi# this also results in a 1595x1132 image, but the fonts are larger.
输出:
using MPL version:0.98.1
DPI:80Default size inInches[8.6.]Which should result in a 640 x 480ImageSizeinInches[16.12.]SizeinInches[16.12.]
Here’s a test script from the above page. It creates test[1-3].png files of different sizes of the same image:
#!/usr/bin/env python
"""
This is a small demo file that helps teach how to adjust figure sizes
for matplotlib
"""
import matplotlib
print "using MPL version:", matplotlib.__version__
matplotlib.use("WXAgg") # do this before pylab so you don'tget the default back end.
import pylab
import numpy as np
# Generate and plot some simple data:
x = np.arange(0, 2*np.pi, 0.1)
y = np.sin(x)
pylab.plot(x,y)
F = pylab.gcf()
# Now check everything with the defaults:
DPI = F.get_dpi()
print "DPI:", DPI
DefaultSize = F.get_size_inches()
print "Default size in Inches", DefaultSize
print "Which should result in a %i x %i Image"%(DPI*DefaultSize[0], DPI*DefaultSize[1])
# the default is 100dpi for savefig:
F.savefig("test1.png")
# this gives me a 797 x 566 pixel image, which is about 100 DPI
# Now make the image twice as big, while keeping the fonts and all the
# same size
F.set_size_inches( (DefaultSize[0]*2, DefaultSize[1]*2) )
Size = F.get_size_inches()
print "Size in Inches", Size
F.savefig("test2.png")
# this results in a 1595x1132 image
# Now make the image twice as big, making all the fonts and lines
# bigger too.
F.set_size_inches( DefaultSize )# resetthe size
Size = F.get_size_inches()
print "Size in Inches", Size
F.savefig("test3.png", dpi = (200)) # change the dpi
# this also results in a 1595x1132 image, but the fonts are larger.
Output:
using MPL version: 0.98.1
DPI: 80
Default size in Inches [ 8. 6.]
Which should result in a 640 x 480 Image
Size in Inches [ 16. 12.]
Size in Inches [ 16. 12.]
Two notes:
The module comments and the actual output differ.
This answer allows easily to combine all three images in one image file to see the difference in sizes.
These will also immediately update your canvas, but only in Matplotlib 2.2.0 and newer.
For Older Versions
You need to specify forward=True explicitly in order to live-update your canvas in versions older than what is specified above. Note that the set_figwidth and set_figheight functions don’t support the forward parameter in versions older than Matplotlib 1.5.0.
回答 8
import matplotlib.pyplot as plt
plt.figure(figsize=(20,10))
plt.plot(x,y)## This is your plot
plt.show()
import matplotlib.pyplot as plt
plt.figure(figsize=(20,10))
plt.plot(x,y) ## This is your plot
plt.show()
You can also use:
fig, ax = plt.subplots(figsize=(20, 10))
回答 9
尝试注释掉该fig = ...行
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
N =50
x = np.random.rand(N)
y = np.random.rand(N)
area = np.pi *(15* np.random.rand(N))**2
fig = plt.figure(figsize=(18,18))
plt.scatter(x, y, s=area, alpha=0.5)
plt.show()
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2
fig = plt.figure(figsize=(18, 18))
plt.scatter(x, y, s=area, alpha=0.5)
plt.show()
回答 10
这对我来说很好:
from matplotlib import pyplot as plt
F = plt.gcf()Size= F.get_size_inches()
F.set_size_inches(Size[0]*2,Size[1]*2, forward=True)# Set forward to True to resize window along with plot in figure.
plt.show()# or plt.imshow(z_array) if using an animation, where z_array is a matrix or numpy array
from matplotlib import pyplot as plt
F = plt.gcf()
Size = F.get_size_inches()
F.set_size_inches(Size[0]*2, Size[1]*2, forward=True) # Set forward to True to resize window along with plot in figure.
plt.show() # or plt.imshow(z_array) if using an animation, where z_array is a matrix or numpy array
Since Matplotlib isn’t able to use the metric system natively, if you want to specify the size of your figure in a reasonable unit of length such as centimeters, you can do the following (code from gns-ank):
def cm2inch(*tupl):
inch = 2.54
if isinstance(tupl[0], tuple):
return tuple(i/inch for i in tupl[0])
else:
return tuple(i/inch for i in tupl)
import matplotlib.pyplot as plt
# here goes your code
fig_size = plt.gcf().get_size_inches()#Get current size
sizefactor =0.8#Set a zoom factor# Modify the current size by the factor
plt.gcf().set_size_inches(sizefactor * fig_size)
Generalizing and simplifying psihodelia’s answer.
If you want to change the current size of the figure by a factor sizefactor
import matplotlib.pyplot as plt
# here goes your code
fig_size = plt.gcf().get_size_inches() #Get current size
sizefactor = 0.8 #Set a zoom factor
# Modify the current size by the factor
plt.gcf().set_size_inches(sizefactor * fig_size)
After changing the current size, it might occur that you have to fine tune the subplot layout. You can do that in the figure window GUI, or by means of the command subplots_adjust
from pylab import figure, axes, pie, title, show
# Make a square figure and axes
figure(1, figsize=(6,6))
ax = axes([0.1,0.1,0.8,0.8])
labels ='Frogs','Hogs','Dogs','Logs'
fracs =[15,30,45,10]
explode =(0,0.05,0,0)
pie(fracs, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True)
title('Raining Hogs and Dogs', bbox={'facecolor':'0.8','pad':5})
show()# Actually, don't show, just save to foo.png
I am writing a quick-and-dirty script to generate plots on the fly. I am using the code below (from Matplotlib documentation) as a starting point:
from pylab import figure, axes, pie, title, show
# Make a square figure and axes
figure(1, figsize=(6, 6))
ax = axes([0.1, 0.1, 0.8, 0.8])
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
fracs = [15, 30, 45, 10]
explode = (0, 0.05, 0, 0)
pie(fracs, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True)
title('Raining Hogs and Dogs', bbox={'facecolor': '0.8', 'pad': 5})
show() # Actually, don't show, just save to foo.png
I don’t want to display the plot on a GUI, instead, I want to save the plot to a file (say foo.png), so that, for example, it can be used in batch scripts. How do I do that?
While the question has been answered, I’d like to add some useful tips when using matplotlib.pyplot.savefig. The file format can be specified by the extension:
from matplotlib import pyplot as plt
plt.savefig('foo.png')
plt.savefig('foo.pdf')
Will give a rasterized or vectorized output respectively, both which could be useful. In addition, you’ll find that pylab leaves a generous, often undesirable, whitespace around the image. Remove it with:
import matplotlib.pyplot as plt
fig, ax = plt.subplots( nrows=1, ncols=1)# create figure & 1 axis
ax.plot([0,1,2],[10,20,3])
fig.savefig('path/to/save/image/to.png')# save the figure to file
plt.close(fig)# close the figure window
As others have said, plt.savefig() or fig1.savefig() is indeed the way to save an image.
However I’ve found that in certain cases the figure is always shown. (eg. with Spyder having plt.ion(): interactive mode = On.) I work around this by forcing the closing of the figure window in my giant loop with plt.close(figure_object) (see documentation), so I don’t have a million open figures during the loop:
import matplotlib.pyplot as plt
fig, ax = plt.subplots( nrows=1, ncols=1 ) # create figure & 1 axis
ax.plot([0,1,2], [10,20,3])
fig.savefig('path/to/save/image/to.png') # save the figure to file
plt.close(fig) # close the figure window
You should be able to re-open the figure later if needed to with fig.show() (didn’t test myself).
They say that the easiest way to prevent the figure from popping up is to use a non-interactive backend (eg. Agg), via matplotib.use(<backend>), eg:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.savefig('myfig')
I still personally prefer using plt.close( fig ), since then you have the option to hide certain figures (during a loop), but still display figures for post-loop data processing. It is probably slower than choosing a non-interactive backend though – would be interesting if someone tested that.
UPDATE: for Spyder, you usually can’t set the backend in this way (Because Spyder usually loads matplotlib early, preventing you from using matplotlib.use()).
Instead, use plt.switch_backend('Agg'), or Turn off “enable support” in the Spyder prefs and run the matplotlib.use('Agg') command yourself.
The other answers are correct. However, I sometimes find that I want to open the figure object later. For example, I might want to change the label sizes, add a grid, or do other processing. In a perfect world, I would simply rerun the code generating the plot, and adapt the settings. Alas, the world is not perfect. Therefore, in addition to saving to PDF or PNG, I add:
with open('some_file.pkl', "wb") as fp:
pickle.dump(fig, fp, protocol=4)
Like this, I can later load the figure object and manipulate the settings as I please.
I also write out the stack with the source-code and locals() dictionary for each function/method in the stack, so that I can later tell exactly what generated the figure.
NB: Be careful, as sometimes this method generates huge files.
回答 6
import datetime
import numpy as np
from matplotlib.backends.backend_pdf importPdfPagesimport matplotlib.pyplot as plt
# Create the PdfPages object to which we will save the pages:# The with statement makes sure that the PdfPages object is closed properly at# the end of the block, even if an Exception occurs.withPdfPages('multipage_pdf.pdf')as pdf:
plt.figure(figsize=(3,3))
plt.plot(range(7),[3,1,4,1,5,9,2],'r-o')
plt.title('Page One')
pdf.savefig()# saves the current figure into a pdf page
plt.close()
plt.rc('text', usetex=True)
plt.figure(figsize=(8,6))
x = np.arange(0,5,0.1)
plt.plot(x, np.sin(x),'b-')
plt.title('Page Two')
pdf.savefig()
plt.close()
plt.rc('text', usetex=False)
fig = plt.figure(figsize=(4,5))
plt.plot(x, x*x,'ko')
plt.title('Page Three')
pdf.savefig(fig)# or you can pass a Figure object to pdf.savefig
plt.close()# We can also set the file's metadata via the PdfPages object:
d = pdf.infodict()
d['Title']='Multipage PDF Example'
d['Author']= u'Jouni K. Sepp\xe4nen'
d['Subject']='How to create a multipage pdf file and set its metadata'
d['Keywords']='PdfPages multipage keywords author title subject'
d['CreationDate']= datetime.datetime(2009,11,13)
d['ModDate']= datetime.datetime.today()
import datetime
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt
# Create the PdfPages object to which we will save the pages:
# The with statement makes sure that the PdfPages object is closed properly at
# the end of the block, even if an Exception occurs.
with PdfPages('multipage_pdf.pdf') as pdf:
plt.figure(figsize=(3, 3))
plt.plot(range(7), [3, 1, 4, 1, 5, 9, 2], 'r-o')
plt.title('Page One')
pdf.savefig() # saves the current figure into a pdf page
plt.close()
plt.rc('text', usetex=True)
plt.figure(figsize=(8, 6))
x = np.arange(0, 5, 0.1)
plt.plot(x, np.sin(x), 'b-')
plt.title('Page Two')
pdf.savefig()
plt.close()
plt.rc('text', usetex=False)
fig = plt.figure(figsize=(4, 5))
plt.plot(x, x*x, 'ko')
plt.title('Page Three')
pdf.savefig(fig) # or you can pass a Figure object to pdf.savefig
plt.close()
# We can also set the file's metadata via the PdfPages object:
d = pdf.infodict()
d['Title'] = 'Multipage PDF Example'
d['Author'] = u'Jouni K. Sepp\xe4nen'
d['Subject'] = 'How to create a multipage pdf file and set its metadata'
d['Keywords'] = 'PdfPages multipage keywords author title subject'
d['CreationDate'] = datetime.datetime(2009, 11, 13)
d['ModDate'] = datetime.datetime.today()
回答 7
在使用plot()和其他函数创建所需的内容之后,可以使用如下子句在绘制到屏幕或文件之间进行选择:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(4,5))# size in inches# use plot(), etc. to create your plot.# Pick one of the following lines to uncomment# save_file = None# save_file = os.path.join(your_directory, your_file_name) if save_file:
plt.savefig(save_file)
plt.close(fig)else:
plt.show()
After using the plot() and other functions to create the content you want, you could use a clause like this to select between plotting to the screen or to file:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(4, 5)) # size in inches
# use plot(), etc. to create your plot.
# Pick one of the following lines to uncomment
# save_file = None
# save_file = os.path.join(your_directory, your_file_name)
if save_file:
plt.savefig(save_file)
plt.close(fig)
else:
plt.show()
import matplotlib.pyplot as plt
plt.savefig("image.png")
In Jupyter Notebook you have to remove plt.show() and add plt.savefig(), together with the rest of the plt-code in one cell.
The image will still show up in your notebook.
Given that today (was not available when this question was made) lots of people use Jupyter Notebook as python console, there is an extremely easy way to save the plots as .png, just call the matplotlib‘s pylab class from Jupyter Notebook, plot the figure ‘inline’ jupyter cells, and then drag that figure/image to a local directory. Don’t forget
%matplotlib inline in the first line!
# Saves a PNG file of the current graph to the folder and updates it every time# (nameOfimage, dpi=(sizeOfimage),Keeps_Labels_From_Disappearing)
plt.savefig(__file__+".png",dpi=(250), bbox_inches='tight')# Hard coded name: './test.png'
Additionally to those above, I added __file__ for the name so the picture and Python file get the same names. I also added few arguments to make It look better:
# Saves a PNG file of the current graph to the folder and updates it every time
# (nameOfimage, dpi=(sizeOfimage),Keeps_Labels_From_Disappearing)
plt.savefig(__file__+".png",dpi=(250), bbox_inches='tight')
# Hard coded name: './test.png'
回答 16
使用时matplotlib.pyplot,必须先保存您的绘图,然后使用以下两行将其关闭:
fig.savefig('plot.png')# save the plot, place the path you want to save the figure in quotation
plt.close(fig)# close the figure window
import matplotlib.pyplot as plt
plt.savefig("myfig.png")
For saving whatever IPhython image that you are displaying. Or on a different note (looking from a different angle), if you ever get to work with open cv, or if you have open cv imported, you can go for:
import cv2
cv2.imwrite(“myfig.png”,image)
But this is just in case if you need to work with Open CV. Otherwise plt.savefig() should be sufficient.
I have a series of 20 plots (not subplots) to be made in a single figure. I want the legend to be outside of the box. At the same time, I do not want to change the axes, as the size of the figure gets reduced. Kindly help me for the following queries:
I want to keep the legend box outside the plot area. (I want the legend to be outside at the right side of the plot area).
Is there anyway that I reduce the font size of the text inside the legend box, so that the size of the legend box will be small.
回答 0
您可以通过创建字体属性来缩小图例文本:
from matplotlib.font_manager importFontProperties
fontP =FontProperties()
fontP.set_size('small')
legend([plot1],"title", prop=fontP)# or add prop=fontP to whatever legend() call you already have
You can make the legend text smaller by creating font properties:
from matplotlib.font_manager import FontProperties
fontP = FontProperties()
fontP.set_size('small')
legend([plot1], "title", prop=fontP)
# or add prop=fontP to whatever legend() call you already have
import matplotlib.pyplot as pltimport numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)for i in xrange(5):
ax.plot(x, i * x, label='$y = %ix$'% i)
ax.legend()
plt.show()
import matplotlib.pyplot as pltimport numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)for i in xrange(5):
ax.plot(x, i * x, label='$y = %ix$'% i)
ax.legend(bbox_to_anchor=(1.1,1.05))
plt.show()
同样,您可以使图例更加水平和/或将其放在图的顶部(我也打开了圆角和简单的阴影):
import matplotlib.pyplot as pltimport numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)for i in xrange(5):
line,= ax.plot(x, i * x, label='$y = %ix$'%i)
ax.legend(loc='upper center', bbox_to_anchor=(0.5,1.05),
ncol=3, fancybox=True, shadow=True)
plt.show()
import matplotlib.pyplot as pltimport numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)for i in xrange(5):
ax.plot(x, i * x, label='$y = %ix$'%i)# Shrink current axis by 20%
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width *0.8, box.height])# Put a legend to the right of the current axis
ax.legend(loc='center left', bbox_to_anchor=(1,0.5))
plt.show()
同样,您可以垂直缩小图,将水平图例放在底部:
import matplotlib.pyplot as pltimport numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)for i in xrange(5):
line,= ax.plot(x, i * x, label='$y = %ix$'%i)# Shrink current axis's height by 10% on the bottom
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height *0.1,
box.width, box.height *0.9])# Put a legend below current axis
ax.legend(loc='upper center', bbox_to_anchor=(0.5,-0.05),
fancybox=True, shadow=True, ncol=5)
plt.show()
There are a number of ways to do what you want. To add to what @inalis and @Navi already said, you can use the bbox_to_anchor keyword argument to place the legend partially outside the axes and/or decrease the font size.
Before you consider decreasing the font size (which can make things awfully hard to read), try playing around with placing the legend in different places:
So, let’s start with a generic example:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(5):
ax.plot(x, i * x, label='$y = %ix$' % i)
ax.legend()
plt.show()
If we do the same thing, but use the bbox_to_anchor keyword argument we can shift the legend slightly outside the axes boundaries:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(5):
ax.plot(x, i * x, label='$y = %ix$' % i)
ax.legend(bbox_to_anchor=(1.1, 1.05))
plt.show()
Similarly, you can make the legend more horizontal and/or put it at the top of the figure (I’m also turning on rounded corners and a simple drop shadow):
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(5):
line, = ax.plot(x, i * x, label='$y = %ix$'%i)
ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.05),
ncol=3, fancybox=True, shadow=True)
plt.show()
Alternatively, you can shrink the current plot’s width, and put the legend entirely outside the axis of the figure (note: if you use tight_layout(), then leave out ax.set_position():
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(5):
ax.plot(x, i * x, label='$y = %ix$'%i)
# Shrink current axis by 20%
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
# Put a legend to the right of the current axis
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.show()
And in a similar manner, you can shrink the plot vertically, and put the a horizontal legend at the bottom:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(5):
line, = ax.plot(x, i * x, label='$y = %ix$'%i)
# Shrink current axis's height by 10% on the bottom
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height * 0.1,
box.width, box.height * 0.9])
# Put a legend below current axis
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05),
fancybox=True, shadow=True, ncol=5)
plt.show()
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,2*np.pi)
colors=["#7aa0c4","#ca82e1","#8bcd50","#e18882"]
fig, axes = plt.subplots(ncols=2)for i in range(4):
axes[i//2].plot(x,np.sin(x+i), color=colors[i],label="y=sin(x+{})".format(i))
fig.legend(loc=7)
fig.tight_layout()
fig.subplots_adjust(right=0.75)
plt.show()
A legend is positioned inside the bounding box of the axes using the loc argument to plt.legend.
E.g. loc="upper right" places the legend in the upper right corner of the bounding box, which by default extents from (0,0) to (1,1) in axes coordinates (or in bounding box notation (x0,y0, width, height)=(0,0,1,1)).
To place the legend outside of the axes bounding box, one may specify a tuple (x0,y0) of axes coordinates of the lower left corner of the legend.
plt.legend(loc=(1.04,0))
However, a more versatile approach would be to manually specify the bounding box into which the legend should be placed, using the bbox_to_anchor argument. One can restrict oneself to supply only the (x0,y0) part of the bbox. This creates a zero span box, out of which the legend will expand in the direction given by the loc argument. E.g.
Details about how to interpret the 4-tuple argument to bbox_to_anchor, as in l4, can be found in this question. The mode="expand" expands the legend horizontally inside the bounding box given by the 4-tuple. For a vertically expanded legend, see this question.
Sometimes it may be useful to specify the bounding box in figure coordinates instead of axes coordinates. This is shown in the example l5 from above, where the bbox_transform argument is used to put the legend in the lower left corner of the figure.
Postprocessing
Having placed the legend outside the axes often leads to the undesired situation that it is completely or partially outside the figure canvas.
Solutions to this problem are:
Adjust the subplot parameters
One can adjust the subplot parameters such, that the axes take less space inside the figure (and thereby leave more space to the legend) by using plt.subplots_adjust. E.g.
plt.subplots_adjust(right=0.7)
leaves 30% space on the right-hand side of the figure, where one could place the legend.
Tight layout
Using plt.tight_layout Allows to automatically adjust the subplot parameters such that the elements in the figure sit tight against the figure edges. Unfortunately, the legend is not taken into account in this automatism, but we can supply a rectangle box that the whole subplots area (including labels) will fit into.
plt.tight_layout(rect=[0,0,0.75,1])
Saving the figure with bbox_inches = "tight"
The argument bbox_inches = "tight" to plt.savefig can be used to save the figure such that all artist on the canvas (including the legend) are fit into the saved area. If needed, the figure size is automatically adjusted.
A figure legend
One may use a legend to the figure instead of the axes, matplotlib.figure.Figure.legend. This has become especially useful for matplotlib version >=2.1, where no special arguments are needed
fig.legend(loc=7)
to create a legend for all artists in the different axes of the figure. The legend is placed using the loc argument, similar to how it is placed inside an axes, but in reference to the whole figure – hence it will be outside the axes somewhat automatically. What remains is to adjust the subplots such that there is no overlap between the legend and the axes. Here the point “Adjust the subplot parameters” from above will be helpful. An example:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,2*np.pi)
colors=["#7aa0c4","#ca82e1" ,"#8bcd50","#e18882"]
fig, axes = plt.subplots(ncols=2)
for i in range(4):
axes[i//2].plot(x,np.sin(x+i), color=colors[i],label="y=sin(x+{})".format(i))
fig.legend(loc=7)
fig.tight_layout()
fig.subplots_adjust(right=0.75)
plt.show()
Legend inside dedicated subplot axes
An alternative to using bbox_to_anchor would be to place the legend in its dedicated subplot axes (lax).
Since the legend subplot should be smaller than the plot, we may use gridspec_kw={"width_ratios":[4,1]} at axes creation.
We can hide the axes lax.axis("off") but still put a legend in. The legend handles and labels need to obtained from the real plot via h,l = ax.get_legend_handles_labels(), and can then be supplied to the legend in the lax subplot, lax.legend(h,l). A complete example is below.
The loc argument can take numbers instead of strings, which make calls shorter, however, they are not very intuitively mapped to each other. Here is the mapping for reference:
To place the legend outside the plot area, use loc and bbox_to_anchor keywords of legend(). For example, the following code will place the legend to the right of the plot area:
figure
x =0:.2:12;
plot(x,besselj(1,x),x,besselj(2,x),x,besselj(3,x));
hleg = legend('First','Second','Third',...'Location','NorthEastOutside')%Make the text of the legend italic and color it brown
set(hleg,'FontAngle','italic','TextColor',[.3,.2,.1])
Short answer: you can use bbox_to_anchor + bbox_extra_artists + bbox_inches='tight'.
Longer answer:
You can use bbox_to_anchor to manually specify the location of the legend box, as some other people have pointed out in the answers.
However, the usual issue is that the legend box is cropped, e.g.:
import matplotlib.pyplot as plt
# data
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]
# Plot
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)
# Add legend, title and axis labels
lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
ax.set_title('Title')
ax.set_xlabel('x label')
ax.set_ylabel('y label')
fig.savefig('image_output.png', dpi=300, format='png')
In order to prevent the legend box from getting cropped, when you save the figure you can use the parameters bbox_extra_artists and bbox_inches to ask savefig to include cropped elements in the saved image:
Example (I only changed the last line to add 2 parameters to fig.savefig()):
import matplotlib.pyplot as plt
# data
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]
# Plot
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)
# Add legend, title and axis labels
lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
ax.set_title('Title')
ax.set_xlabel('x label')
ax.set_ylabel('y label')
fig.savefig('image_output.png', dpi=300, format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')
I wish that matplotlib would natively allow outside location for the legend box as Matlab does:
figure
x = 0:.2:12;
plot(x,besselj(1,x),x,besselj(2,x),x,besselj(3,x));
hleg = legend('First','Second','Third',...
'Location','NorthEastOutside')
% Make the text of the legend italic and color it brown
set(hleg,'FontAngle','italic','TextColor',[.3,.2,.1])
In addition to all the excellent answers here, newer versions of matplotlib and pylab can automatically determine where to put the legend without interfering with the plots, if possible.
pylab.legend(loc='best')
This will automatically place the legend away from the data if possible!
However, if there is no place to put the legend without overlapping the data, then you’ll want to try one of the other answers; using loc="best" will never put the legend outside of the plot.
import matplotlib.pylab as plt
import numpy as np
#define the figure and get an axes instance
fig = plt.figure()
ax = fig.add_subplot(111)#plot the data
x = np.arange(-5,6)
ax.plot(x, x*x, label='y = x^2')
ax.plot(x, x*x*x, label='y = x^3')
ax.legend().draggable()
plt.show()
Short Answer: Invoke draggable on the legend and interactively move it wherever you want:
ax.legend().draggable()
Long Answer: If you rather prefer to place the legend interactively/manually rather than programmatically, you can toggle the draggable mode of the legend so that you can drag it to wherever you want. Check the example below:
import matplotlib.pylab as plt
import numpy as np
#define the figure and get an axes instance
fig = plt.figure()
ax = fig.add_subplot(111)
#plot the data
x = np.arange(-5, 6)
ax.plot(x, x*x, label='y = x^2')
ax.plot(x, x*x*x, label='y = x^3')
ax.legend().draggable()
plt.show()
回答 8
并非完全符合您的要求,但我发现它可以替代同一问题。使图例半透明,如下所示:
使用以下方法执行此操作:
fig = pylab.figure()
ax = fig.add_subplot(111)
ax.plot(x,y,label=label,color=color)# Make the legend transparent:
ax.legend(loc=2,fontsize=10,fancybox=True).get_frame().set_alpha(0.5)# Make a transparent text box
ax.text(0.02,0.02,yourstring, verticalalignment='bottom',
horizontalalignment='left',
fontsize=10,
bbox={'facecolor':'white','alpha':0.6,'pad':10},
transform=self.ax.transAxes)
import plotly
import math
import random
import numpy as np
然后,安装Plotly:
un='IPython.Demo'
k='1fw3zw2o13'
py = plotly.plotly(username=un, key=k)def sin(x,n):
sine =0for i in range(n):
sign =(-1)**i
sine = sine +((x**(2.0*i+1))/math.factorial(2*i+1))*sign
return sine
x = np.arange(-12,12,0.1)
anno ={'text':'$\\sum_{k=0}^{\\infty} \\frac {(-1)^k x^{1+2k}}{(1 + 2k)!}$','x':0.3,'y':0.6,'xref':"paper",'yref':"paper",'showarrow':False,'font':{'size':24}}
l ={'annotations':[anno],'title':'Taylor series of sine','xaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},'yaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},'legend':{'font':{'size':16},'bordercolor':'white','bgcolor':'#fcfcfc'}}
py.iplot([{'x':x,'y':sin(x,1),'line':{'color':'#e377c2'},'name':'$x\\\\$'},\
{'x':x,'y':sin(x,2),'line':{'color':'#7f7f7f'},'name':'$ x-\\frac{x^3}{6}$'},\
{'x':x,'y':sin(x,3),'line':{'color':'#bcbd22'},'name':'$ x-\\frac{x^3}{6}+\\frac{x^5}{120}$'},\
{'x':x,'y':sin(x,4),'line':{'color':'#17becf'},'name':'$ x-\\frac{x^5}{120}$'}], layout=l)
As noted, you could also place the legend in the plot, or slightly off it to the edge as well. Here is an example using the Plotly Python API, made with an IPython Notebook. I’m on the team.
To begin, you’ll want to install the necessary packages:
import plotly
import math
import random
import numpy as np
Then, install Plotly:
un='IPython.Demo'
k='1fw3zw2o13'
py = plotly.plotly(username=un, key=k)
def sin(x,n):
sine = 0
for i in range(n):
sign = (-1)**i
sine = sine + ((x**(2.0*i+1))/math.factorial(2*i+1))*sign
return sine
x = np.arange(-12,12,0.1)
anno = {
'text': '$\\sum_{k=0}^{\\infty} \\frac {(-1)^k x^{1+2k}}{(1 + 2k)!}$',
'x': 0.3, 'y': 0.6,'xref': "paper", 'yref': "paper",'showarrow': False,
'font':{'size':24}
}
l = {
'annotations': [anno],
'title': 'Taylor series of sine',
'xaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
'yaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
'legend':{'font':{'size':16},'bordercolor':'white','bgcolor':'#fcfcfc'}
}
py.iplot([{'x':x, 'y':sin(x,1), 'line':{'color':'#e377c2'}, 'name':'$x\\\\$'},\
{'x':x, 'y':sin(x,2), 'line':{'color':'#7f7f7f'},'name':'$ x-\\frac{x^3}{6}$'},\
{'x':x, 'y':sin(x,3), 'line':{'color':'#bcbd22'},'name':'$ x-\\frac{x^3}{6}+\\frac{x^5}{120}$'},\
{'x':x, 'y':sin(x,4), 'line':{'color':'#17becf'},'name':'$ x-\\frac{x^5}{120}$'}], layout=l)
This creates your graph, and allows you a chance to keep the legend within the plot itself. The default for the legend if it is not set is to place it in the plot, as shown here.
For an alternative placement, you can closely align the edge of the graph and border of the legend, and remove border lines for a closer fit.
You can move and re-style the legend and graph with code, or with the GUI. To shift the legend, you have the following options to position the legend inside the graph by assigning x and y values of <= 1. E.g :
{"x" : 0,"y" : 0} — Bottom Left
{"x" : 1, "y" : 0} — Bottom Right
{"x" : 1, "y" : 1} — Top Right
{"x" : 0, "y" : 1} — Top Left
{"x" :.5, "y" : 0} — Bottom Center
{"x": .5, "y" : 1} — Top Center
In this case, we choose the upper right, legendstyle = {"x" : 1, "y" : 1}, also described in the documentation:
回答 10
这些方针对我有用。从Joe的一些代码开始,此方法修改了窗口的宽度,以自动适应图右边的图例。
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)for i in xrange(5):
ax.plot(x, i * x, label='$y = %ix$'%i)# Put a legend to the right of the current axis
leg = ax.legend(loc='center left', bbox_to_anchor=(1,0.5))
plt.draw()# Get the ax dimensions.
box = ax.get_position()
xlocs =(box.x0,box.x1)
ylocs =(box.y0,box.y1)# Get the figure size in inches and the dpi.
w, h = fig.get_size_inches()
dpi = fig.get_dpi()# Get the legend size, calculate new window width and change the figure size.
legWidth = leg.get_window_extent().width
winWidthNew = w*dpi+legWidth
fig.set_size_inches(winWidthNew/dpi,h)# Adjust the window size to fit the figure.
mgr = plt.get_current_fig_manager()
mgr.window.wm_geometry("%ix%i"%(winWidthNew,mgr.window.winfo_height()))# Rescale the ax to keep its original size.
factor = w*dpi/winWidthNew
x0 = xlocs[0]*factor
x1 = xlocs[1]*factor
width = box.width*factor
ax.set_position([x0,ylocs[0],x1-x0,ylocs[1]-ylocs[0]])
plt.draw()
Something along these lines worked for me. Starting with a bit of code taken from Joe, this method modifies the window width to automatically fit a legend to the right of the figure.
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
for i in xrange(5):
ax.plot(x, i * x, label='$y = %ix$'%i)
# Put a legend to the right of the current axis
leg = ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.draw()
# Get the ax dimensions.
box = ax.get_position()
xlocs = (box.x0,box.x1)
ylocs = (box.y0,box.y1)
# Get the figure size in inches and the dpi.
w, h = fig.get_size_inches()
dpi = fig.get_dpi()
# Get the legend size, calculate new window width and change the figure size.
legWidth = leg.get_window_extent().width
winWidthNew = w*dpi+legWidth
fig.set_size_inches(winWidthNew/dpi,h)
# Adjust the window size to fit the figure.
mgr = plt.get_current_fig_manager()
mgr.window.wm_geometry("%ix%i"%(winWidthNew,mgr.window.winfo_height()))
# Rescale the ax to keep its original size.
factor = w*dpi/winWidthNew
x0 = xlocs[0]*factor
x1 = xlocs[1]*factor
width = box.width*factor
ax.set_position([x0,ylocs[0],x1-x0,ylocs[1]-ylocs[0]])
plt.draw()
It’s worth refreshing this question, as newer versions of Matplotlib have made it much easier to position the legend outside the plot. I produced this example with Matplotlib version 3.1.1.
Users can pass a 2-tuple of coordinates to the loc parameter to position the legend anywhere in the bounding box. The only gotcha is you need to run plt.tight_layout() to get matplotlib to recompute the plot dimensions so the legend is visible:
You can also try figlegend. It is possible to create a legend independent of any Axes object. However, you may need to create some “dummy” Paths to make sure the formatting for the objects gets passed on correctly.
Here is an example from the matplotlib tutorial found here. This is one of the more simpler examples but I added transparency to the legend and added plt.show() so you can paste this into the interactive shell and get a result:
The solution that worked for me when I had huge legend was to use extra empty image layout.
In following example I made 4 rows and at the bottom I plot image with offset for legend (bbox_to_anchor) at the top it does not get cut.
Here’s another solution, similar to adding bbox_extra_artists and bbox_inches, where you don’t have to have your extra artists in the scope of your savefig call. I came up with this since I generate most of my plot inside functions.
Instead of adding all your additions to the bounding box when you want to write it out, you can add them ahead of time to the Figure‘s artists. Using something similar to Franck Dernoncourt’s answer above:
import matplotlib.pyplot as plt
# data
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]
# plotting function
def gen_plot(x, y):
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)
lgd = ax.legend( [ "Lag " + str(lag) for lag in all_x], loc="center right", bbox_to_anchor=(1.3, 0.5))
fig.artists.append(lgd) # Here's the change
ax.set_title("Title")
ax.set_xlabel("x label")
ax.set_ylabel("y label")
return fig
# plotting
fig = gen_plot(all_x, all_y)
# No need for `bbox_extra_artists`
fig.savefig("image_output.png", dpi=300, format="png", bbox_inches="tight")
from matplotlib as plt
from matplotlib.font_manager importFontProperties......
t = A[:,0]
sensors = A[:,index_lst]for i in range(sensors.shape[1]):
plt.plot(t,sensors[:,i])
plt.xlabel('s')
plt.ylabel('°C')
lgd = plt.legend(b,loc='center left', bbox_to_anchor=(1,0.5),fancybox =True, shadow =True)
don’t know if you already sorted out your issue…probably yes, but…
I simply used the string ‘outside’ for the location, like in matlab.
I imported pylab from matplotlib.
see the code as follow:
from matplotlib as plt
from matplotlib.font_manager import FontProperties
...
...
t = A[:,0]
sensors = A[:,index_lst]
for i in range(sensors.shape[1]):
plt.plot(t,sensors[:,i])
plt.xlabel('s')
plt.ylabel('°C')
lgd = plt.legend(b,loc='center left', bbox_to_anchor=(1, 0.5),fancybox = True, shadow = True)
Copyright 2015 Donne Martin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.