if __name__ =='__main__':PyPlot.plot(total_lengths, sort_times_bubble,'b-',
total_lengths, sort_times_ins,'r-',
total_lengths, sort_times_merge_r,'g+',
total_lengths, sort_times_merge_i,'p-',)PyPlot.title("Combined Statistics")PyPlot.xlabel("Length of list (number)")PyPlot.ylabel("Time taken (seconds)")PyPlot.show()
TL;DR -> How can one create a legend for a line graph in Matplotlib‘s PyPlot without creating any extra variables?
Please consider the graphing script below:
if __name__ == '__main__':
PyPlot.plot(total_lengths, sort_times_bubble, 'b-',
total_lengths, sort_times_ins, 'r-',
total_lengths, sort_times_merge_r, 'g+',
total_lengths, sort_times_merge_i, 'p-', )
PyPlot.title("Combined Statistics")
PyPlot.xlabel("Length of list (number)")
PyPlot.ylabel("Time taken (seconds)")
PyPlot.show()
As you can see, this is a very basic use of matplotlib‘s PyPlot. This ideally generates a graph like the one below:
Nothing special, I know. However, it is unclear what data is being plotted where (I’m trying to plot the data of some sorting algorithms, length against time taken, and I’d like to make sure people know which line is which). Thus, I need a legend, however, taking a look at the following example below(from the official site):
ax = subplot(1,1,1)
p1, = ax.plot([1,2,3], label="line 1")
p2, = ax.plot([3,2,1], label="line 2")
p3, = ax.plot([2,3,1], label="line 3")
handles, labels = ax.get_legend_handles_labels()
# reverse the order
ax.legend(handles[::-1], labels[::-1])
# or sort them by labels
import operator
hl = sorted(zip(handles, labels),
key=operator.itemgetter(1))
handles2, labels2 = zip(*hl)
ax.legend(handles2, labels2)
You will see that I need to create an extra variable ax. How can I add a legend to my graph without having to create this extra variable and retaining the simplicity of my current script?
You can access the Axes instance (ax) with plt.gca(). In this case, you can use
plt.gca().legend()
You can do this either by using the label= keyword in each of your plt.plot() calls or by assigning your labels as a tuple or list within legend, as in this working example:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-0.75,1,100)
y0 = np.exp(2 + 3*x - 7*x**3)
y1 = 7-4*np.sin(4*x)
plt.plot(x,y0,x,y1)
plt.gca().legend(('y0','y1'))
plt.show()
However, if you need to access the Axes instance more that once, I do recommend saving it to the variable ax with
import math
import matplotlib.pyplot as plt
x=[]for i in range(-314,314):
x.append(i/100)
ysin=[math.sin(i)for i in x]
ycos=[math.cos(i)for i in x]
plt.plot(x,ysin,label='sin(x)')#specify label for the corresponding curve
plt.plot(x,ycos,label='cos(x)')
plt.xticks([-3.14,-1.57,0,1.57,3.14],['-$\pi$','-$\pi$/2',0,'$\pi$/2','$\pi$'])
plt.legend()
plt.show()
A simple plot for sine and cosine curves with a legend.
Used matplotlib.pyplot
import math
import matplotlib.pyplot as plt
x=[]
for i in range(-314,314):
x.append(i/100)
ysin=[math.sin(i) for i in x]
ycos=[math.cos(i) for i in x]
plt.plot(x,ysin,label='sin(x)') #specify label for the corresponding curve
plt.plot(x,ycos,label='cos(x)')
plt.xticks([-3.14,-1.57,0,1.57,3.14],['-$\pi$','-$\pi$/2',0,'$\pi$/2','$\pi$'])
plt.legend()
plt.show()
# Dependenciesimport numpy as np
import matplotlib.pyplot as plt
#Set Axes# Set x axis to numerical value for month
x_axis_data = np.arange(1,13,1)
x_axis_data
# Average weather temp
points =[39,42,51,62,72,82,86,84,77,65,55,44]# Plot the line
plt.plot(x_axis_data, points)
plt.show()# Convert to Celsius C = (F-32) * 0.56
points_C =[round((x-32)*0.56,2)for x in points]
points_C
# Plot using Celsius
plt.plot(x_axis_data, points_C)
plt.show()# Plot both on the same chart
plt.plot(x_axis_data, points)
plt.plot(x_axis_data, points_C)#Line colors
plt.plot(x_axis_data, points,"-b", label="F")
plt.plot(x_axis_data, points_C,"-r", label="C")#locate legend
plt.legend(loc="upper left")
plt.show()
After these instructions in the Python interpreter one gets a window with a plot:
from matplotlib.pyplot import *
plot([1,2,3])
show()
# other code
Unfortunately, I don’t know how to continue to interactively explore the figure created by show() while the program does further calculations.
Is it possible at all? Sometimes calculations are long and it would help if they would proceed during examination of intermediate results.
回答 0
使用matplotlib不会阻塞的呼叫:
使用draw():
from matplotlib.pyplot import plot, draw, show
plot([1,2,3])
draw()print'continue computation'# at the end call show to ensure window won't close.
show()
使用交互模式:
from matplotlib.pyplot import plot, ion, show
ion()# enables interactive mode
plot([1,2,3])# result shows immediatelly (implicit draw())print'continue computation'# at the end call show to ensure window won't close.
show()
from matplotlib.pyplot import plot, draw, show
plot([1,2,3])
draw()
print('continue computation')
# at the end call show to ensure window won't close.
show()
Using interactive mode:
from matplotlib.pyplot import plot, ion, show
ion() # enables interactive mode
plot([1,2,3]) # result shows immediatelly (implicit draw())
print('continue computation')
# at the end call show to ensure window won't close.
show()
回答 1
使用关键字“ block”来覆盖阻止行为,例如
from matplotlib.pyplot import show, plot
plot(1)
show(block=False)# your code
from multiprocessing importProcessfrom matplotlib.pyplot import plot, show
def plot_graph(*args):for data in args:
plot(data)
show()
p =Process(target=plot_graph, args=([1,2,3],))
p.start()print'yay'print'computation continues...'print'that rocks.'print'Now lets wait for the graph be closed to continue...:'
p.join()
It is better to always check with the library you are using if it supports usage in a non-blocking way.
But if you want a more generic solution, or if there is no other way, you can run anything that blocks in a separated process by using the multprocessing module included in python. Computation will continue:
from multiprocessing import Process
from matplotlib.pyplot import plot, show
def plot_graph(*args):
for data in args:
plot(data)
show()
p = Process(target=plot_graph, args=([1, 2, 3],))
p.start()
print 'yay'
print 'computation continues...'
print 'that rocks.'
print 'Now lets wait for the graph be closed to continue...:'
p.join()
That has the overhead of launching a new process, and is sometimes harder to debug on complex scenarios, so I’d prefer the other solution (using matplotlib‘s nonblocking API calls)
回答 3
尝试
import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.show(block=False)# other code# [...]# Put
plt.show()# at the very end of your script to make sure Python doesn't bail out# before you finished examining.
import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.show(block=False)
# other code
# [...]
# Put
plt.show()
# at the very end of your script to make sure Python doesn't bail out
# before you finished examining.
In non-interactive mode, display all figures and block until the figures have been closed; in interactive mode it has no effect unless figures were created prior to a change from non-interactive to interactive mode (not recommended). In that case it displays the figures but does not block.
A single experimental keyword argument, block, may be set to True or False to override the blocking behavior described above.
plt.imshow(*something*)
plt.colorbar()
plt.xlabel("true ")
plt.ylabel("predicted ")
plt.title(" the matrix")# Add block = False
plt.show(block =False)################################# OTHER CALCULATIONS AND CODE HERE ! ! !################################# the next command is the last line of my script
plt.show()
IMPORTANT: Just to make something clear. I assume that the commands are inside a .py script and the script is called using e.g. python script.py from the console.
A simple way that works for me is:
Use the block = False inside show : plt.show(block = False)
Use another show() at the end of the .py script.
Example ofscript.py file:
plt.imshow(*something*)
plt.colorbar()
plt.xlabel("true ")
plt.ylabel("predicted ")
plt.title(" the matrix")
# Add block = False
plt.show(block = False)
################################
# OTHER CALCULATIONS AND CODE HERE ! ! !
################################
# the next command is the last line of my script
plt.show()
import sys
import gtk, gobject
import matplotlib
matplotlib.use('GTKAgg')import pylab as p
import numpy as nx
import time
import threading
ax = p.subplot(111)
canvas = ax.figure.canvas
# for profiling
tstart = time.time()# create the initial line
x = nx.arange(0,2*nx.pi,0.01)
line,= ax.plot(x, nx.sin(x), animated=True)# save the clean slate background -- everything but the animated line# is drawn and saved in the pixel buffer background
background = canvas.copy_from_bbox(ax.bbox)# just a plain global var to pass data (from main, to plot update thread)global mypass
# http://docs.python.org/library/multiprocessing.html#pipes-and-queuesfrom multiprocessing importPipeglobal pipe1main, pipe1upd
pipe1main, pipe1upd =Pipe()# the kind of processing we might want to do in a main() function,# will now be done in a "main thread" - so it can run in# parallel with gobject.idle_add(update_line)def threadMainTest():global mypass
global runthread
global pipe1main
print"tt"
interncount =1while runthread:
mypass +=1if mypass >100:# start "speeding up" animation, only after 100 counts have passed
interncount *=1.03
pipe1main.send(interncount)
time.sleep(0.01)return# main plot / GUI updatedef update_line(*args):global mypass
global t0
global runthread
global pipe1upd
ifnot runthread:returnFalseif pipe1upd.poll():# check first if there is anything to receive
myinterncount = pipe1upd.recv()
update_line.cnt = mypass
# restore the clean slate background
canvas.restore_region(background)# update the data
line.set_ydata(nx.sin(x+(update_line.cnt+myinterncount)/10.0))# just draw the animated artist
ax.draw_artist(line)# just redraw the axes rectangle
canvas.blit(ax.bbox)if update_line.cnt>=500:# print the timing info and quitprint'FPS:', update_line.cnt/(time.time()-tstart)
runthread=0
t0.join(1)print"exiting"
sys.exit(0)returnTrueglobal runthread
update_line.cnt =0
mypass =0
runthread=1
gobject.idle_add(update_line)global t0
t0 = threading.Thread(target=threadMainTest)
t0.start()# start the graphics update thread
p.show()print"out"# will never print - show() blocks indefinitely!
Well, I had great trouble figuring out the non-blocking commands… But finally, I managed to rework the “Cookbook/Matplotlib/Animations – Animating selected plot elements” example, so it works with threads (and passes data between threads either via global variables, or through a multiprocess Pipe) on Python 2.6.5 on Ubuntu 10.04.
import sys
import gtk, gobject
import matplotlib
matplotlib.use('GTKAgg')
import pylab as p
import numpy as nx
import time
import threading
ax = p.subplot(111)
canvas = ax.figure.canvas
# for profiling
tstart = time.time()
# create the initial line
x = nx.arange(0,2*nx.pi,0.01)
line, = ax.plot(x, nx.sin(x), animated=True)
# save the clean slate background -- everything but the animated line
# is drawn and saved in the pixel buffer background
background = canvas.copy_from_bbox(ax.bbox)
# just a plain global var to pass data (from main, to plot update thread)
global mypass
# http://docs.python.org/library/multiprocessing.html#pipes-and-queues
from multiprocessing import Pipe
global pipe1main, pipe1upd
pipe1main, pipe1upd = Pipe()
# the kind of processing we might want to do in a main() function,
# will now be done in a "main thread" - so it can run in
# parallel with gobject.idle_add(update_line)
def threadMainTest():
global mypass
global runthread
global pipe1main
print "tt"
interncount = 1
while runthread:
mypass += 1
if mypass > 100: # start "speeding up" animation, only after 100 counts have passed
interncount *= 1.03
pipe1main.send(interncount)
time.sleep(0.01)
return
# main plot / GUI update
def update_line(*args):
global mypass
global t0
global runthread
global pipe1upd
if not runthread:
return False
if pipe1upd.poll(): # check first if there is anything to receive
myinterncount = pipe1upd.recv()
update_line.cnt = mypass
# restore the clean slate background
canvas.restore_region(background)
# update the data
line.set_ydata(nx.sin(x+(update_line.cnt+myinterncount)/10.0))
# just draw the animated artist
ax.draw_artist(line)
# just redraw the axes rectangle
canvas.blit(ax.bbox)
if update_line.cnt>=500:
# print the timing info and quit
print 'FPS:' , update_line.cnt/(time.time()-tstart)
runthread=0
t0.join(1)
print "exiting"
sys.exit(0)
return True
global runthread
update_line.cnt = 0
mypass = 0
runthread=1
gobject.idle_add(update_line)
global t0
t0 = threading.Thread(target=threadMainTest)
t0.start()
# start the graphics update thread
p.show()
print "out" # will never print - show() blocks indefinitely!
In many cases it is more convenient til save the image as a .png file on the hard drive. Here is why:
Advantages:
You can open it, have a look at it and close it down any time in the process. This is particularly convenient when your application is running for a long
time.
Nothing pops up and you are not forced to have the windows open. This is particularly convenient when you are dealing with many figures.
Your image is accessible for later reference and is not lost when closing the figure window.
Drawback:
The only thing I can think of is that you will have to go and finder the folder and open the image yourself.
If you are working in console, i.e. IPython you could use plt.show(block=False) as pointed out in the other answers. But if you’re lazy you could just type:
import matplotlib.pyplot as plt
plt.scatter([0],[1])
plt.draw()
plt.show(block=False)for i in range(10):
plt.scatter([i],[i+1])
plt.draw()
plt.pause(0.001)
I had to also add plt.pause(0.001) to my code to really make it working inside a for loop (otherwise it would only show the first and last plot):
import matplotlib.pyplot as plt
plt.scatter([0], [1])
plt.draw()
plt.show(block=False)
for i in range(10):
plt.scatter([i], [i+1])
plt.draw()
plt.pause(0.001)
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(x,y)# set processing to continue when window closeddef onclose(event):
fig.canvas.stop_event_loop()
fig.canvas.mpl_connect('close_event', onclose)
fig.show()# this call does not block on my system
fig.canvas.start_event_loop_default()# block here until window closed# continue with further processing, perhaps using result from callbacks
但是请注意,canvas.start_event_loop_default()产生以下警告:
C:\Python26\lib\site-packages\matplotlib\backend_bases.py:2051:DeprecationWarning:Using default event loop until function specific to this GUI is implemented
warnings.warn(str,DeprecationWarning)
On my system show() does not block, although I wanted the script to wait for the user to interact with the graph (and collect data using ‘pick_event’ callbacks) before continuing.
In order to block execution until the plot window is closed, I used the following:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(x,y)
# set processing to continue when window closed
def onclose(event):
fig.canvas.stop_event_loop()
fig.canvas.mpl_connect('close_event', onclose)
fig.show() # this call does not block on my system
fig.canvas.start_event_loop_default() # block here until window closed
# continue with further processing, perhaps using result from callbacks
Note, however, that canvas.start_event_loop_default() produced the following warning:
C:\Python26\lib\site-packages\matplotlib\backend_bases.py:2051: DeprecationWarning: Using default event loop until function specific to this GUI is implemented
warnings.warn(str,DeprecationWarning)
from contextlib import contextmanager
@contextmanagerdef keep_plots_open(keep_show_open_on_exit=True, even_when_error=True):'''
To continue excecuting code when plt.show() is called
and keep the plot on displaying before this contex manager exits
(even if an error caused the exit).
'''import matplotlib.pyplot
show_original = matplotlib.pyplot.show
def show_replacement(*args,**kwargs):
kwargs['block']=False
show_original(*args,**kwargs)
matplotlib.pyplot.show = show_replacement
pylab_exists =Truetry:import pylab
exceptImportError:
pylab_exists =Falseif pylab_exists:
pylab.show = show_replacement
try:yieldexceptException, err:if keep_show_open_on_exit and even_when_error:print"*********************************************"print"Error early edition while waiting for show():"print"*********************************************"import traceback
print traceback.format_exc()
show_original()print"*********************************************"raisefinally:
matplotlib.pyplot.show = show_original
if pylab_exists:
pylab.show = show_original
if keep_show_open_on_exit:
show_original()# ***********************# Running example# ***********************import pylab as pl
import time
if __name__ =='__main__':with keep_plots_open():
pl.figure('a')
pl.plot([1,2,3],[4,5,6])
pl.plot([3,2,1],[4,5,6])
pl.show()
pl.figure('b')
pl.plot([1,2,3],[4,5,6])
pl.show()
time.sleep(1)print'...'
time.sleep(1)print'...'
time.sleep(1)print'...'
this_will_surely_cause_an_error
I also wanted my plots to display run the rest of the code (and then keep on displaying) even if there is an error (I sometimes use plots for debugging). I coded up this little hack so that any plots inside this with statement behave as such.
This is probably a bit too non-standard and not advisable for production code. There is probably a lot of hidden “gotchas” in this code.
from contextlib import contextmanager
@contextmanager
def keep_plots_open(keep_show_open_on_exit=True, even_when_error=True):
'''
To continue excecuting code when plt.show() is called
and keep the plot on displaying before this contex manager exits
(even if an error caused the exit).
'''
import matplotlib.pyplot
show_original = matplotlib.pyplot.show
def show_replacement(*args, **kwargs):
kwargs['block'] = False
show_original(*args, **kwargs)
matplotlib.pyplot.show = show_replacement
pylab_exists = True
try:
import pylab
except ImportError:
pylab_exists = False
if pylab_exists:
pylab.show = show_replacement
try:
yield
except Exception, err:
if keep_show_open_on_exit and even_when_error:
print "*********************************************"
print "Error early edition while waiting for show():"
print "*********************************************"
import traceback
print traceback.format_exc()
show_original()
print "*********************************************"
raise
finally:
matplotlib.pyplot.show = show_original
if pylab_exists:
pylab.show = show_original
if keep_show_open_on_exit:
show_original()
# ***********************
# Running example
# ***********************
import pylab as pl
import time
if __name__ == '__main__':
with keep_plots_open():
pl.figure('a')
pl.plot([1,2,3], [4,5,6])
pl.plot([3,2,1], [4,5,6])
pl.show()
pl.figure('b')
pl.plot([1,2,3], [4,5,6])
pl.show()
time.sleep(1)
print '...'
time.sleep(1)
print '...'
time.sleep(1)
print '...'
this_will_surely_cause_an_error
If/when I implement a proper “keep the plots open (even if an error occurs) and allow new plots to be shown”, I would want the script to properly exit if no user interference tells it otherwise (for batch execution purposes).
plt.figure(1)
plt.imshow(your_first_image)
plt.figure(2)
plt.imshow(your_second_image)
plt.show(block=False)# That's important
raw_input("Press ENTER to exist")# Useful when you run your Python script from the terminal and you want to hold the running to see your figures until you press Enter
plt.figure(1)
plt.imshow(your_first_image)
plt.figure(2)
plt.imshow(your_second_image)
plt.show(block=False) # That's important
raw_input("Press ENTER to exist") # Useful when you run your Python script from the terminal and you want to hold the running to see your figures until you press Enter
#!/usr/bin/python3import time
import multiprocessing
import os
def plot_graph(data):from matplotlib.pyplot import plot, draw, show
print("entered plot_graph()")
plot(data)
show()# this will block and remain a viable process as long as the figure window is openprint("exiting plot_graph() process")if __name__ =="__main__":print("starting __main__")
multiprocessing.Process(target=plot_graph, args=([1,2,3],)).start()
time.sleep(5)print("exiting main")
os._exit(0)# this exits immediately with no cleanup or buffer flushing
The OP asks about detatching matplotlib plots. Most answers assume command execution from within a python interpreter. The use-case presented here is my preference for testing code in a terminal (e.g. bash) where a file.py is run and you want the plot(s) to come up but the python script to complete and return to a command prompt.
This stand-alone file uses multiprocessing to launch a separate process for plotting data with matplotlib. The main thread exits using the os._exit(1) mentioned in this post. The os._exit() forces main to exit but leaves the matplotlib child process alive and responsive until the plot window is closed. It’s a separate process entirely.
This approach is a bit like a Matlab development session with figure windows that come up with a responsive command prompt. With this approach, you have lost all contact with the figure window process, but, that’s ok for development and debugging. Just close the window and keep testing.
multiprocessing is designed for python-only code execution which makes it perhaps better suited than subprocess. multiprocessing is cross-platform so this should work well in Windows or Mac with little or no adjustment. There is no need to check the underlying operating system. This was tested on linux, Ubuntu 18.04LTS.
#!/usr/bin/python3
import time
import multiprocessing
import os
def plot_graph(data):
from matplotlib.pyplot import plot, draw, show
print("entered plot_graph()")
plot(data)
show() # this will block and remain a viable process as long as the figure window is open
print("exiting plot_graph() process")
if __name__ == "__main__":
print("starting __main__")
multiprocessing.Process(target=plot_graph, args=([1, 2, 3],)).start()
time.sleep(5)
print("exiting main")
os._exit(0) # this exits immediately with no cleanup or buffer flushing
Running file.py brings up a figure window, then __main__ exits but the multiprocessing + matplotlib figure window remains responsive with zoom, pan, and other buttons because it is an independent process.
Check the processes at the bash command prompt with:
In my opinion, the answers in this thread provide methods which don’t work for every systems and in more complex situations like animations. I suggest to have a look at the answer of MiKTeX in the following thread, where a robust method has been found:
How to wait until matplotlib animation ends?
import matplotlib.pyplot as plt
#code generating the plot in a loop or function#saving the plot
plt.savefig(var+'_plot.png',bbox_inches='tight', dpi=250)#you can allways reopen the plot using
os.system(var+'_plot.png')# unfortunately .png allows no interaction.#the following avoids plot blocking the execution while in non-interactive mode
plt.show(block=False)#and the following closes the plot while next iteration will generate new instance.
plt.close()
While not directly answering OPs request, Im posting this workaround since it may help somebody in this situation:
Im creating an .exe with pyinstaller since I cannot install python where I need to generate the plots, so I need the python script to generate the plot, save it as .png, close it and continue with the next, implemented as several plots in a loop or using a function.
for this Im using:
import matplotlib.pyplot as plt
#code generating the plot in a loop or function
#saving the plot
plt.savefig(var+'_plot.png',bbox_inches='tight', dpi=250)
#you can allways reopen the plot using
os.system(var+'_plot.png') # unfortunately .png allows no interaction.
#the following avoids plot blocking the execution while in non-interactive mode
plt.show(block=False)
#and the following closes the plot while next iteration will generate new instance.
plt.close()
Where “var” identifies the plot in the loop so it wont be overwritten.
from matplotlib import pyplot as plt
plt.plot(range(10))
plt.tick_params(
axis='x',# changes apply to the x-axis
which='both',# both major and minor ticks are affected
bottom=False,# ticks along the bottom edge are off
top=False,# ticks along the top edge are off
labelbottom=False)# labels along the bottom edge are off
plt.show()
plt.savefig('plot')
plt.clf()
The tick_params method is very useful for stuff like this. This code turns off major and minor ticks and removes the labels from the x-axis.
from matplotlib import pyplot as plt
plt.plot(range(10))
plt.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
labelbottom=False) # labels along the bottom edge are off
plt.show()
plt.savefig('plot')
plt.clf()
Not exactly what the OP was asking for, but a simple way to disable all axes lines, ticks and labels is to simply call:
plt.axis('off')
回答 2
另外,您可以传递一个空的刻度位置并将其标记为
# for matplotlib.pyplot# ---------------------
plt.xticks([],[])# for axis object# ---------------# from Anakhand May 5 at 13:08# for major ticks
ax.set_xticks([])# for minor ticks
ax.set_xticks([], minor=True)
Alternatively, you can pass an empty tick position and label as
# for matplotlib.pyplot
# ---------------------
plt.xticks([], [])
# for axis object
# ---------------
# from Anakhand May 5 at 13:08
# for major ticks
ax.set_xticks([])
# for minor ticks
ax.set_xticks([], minor=True)
This snippet might help in removing the xticks only.
from matplotlib import pyplot as plt
plt.xticks([])
This snippet might help in removing the xticks and yticks both.
from matplotlib import pyplot as plt
plt.xticks([]),plt.yticks([])
回答 7
# remove all the ticks (both axes), and tick labels on the Y axis
plt.tick_params(top='off', bottom='off', left='off', right='off', labelleft='off', labelbottom='on')
# remove all the ticks (both axes), and tick labels on the Y axis
plt.tick_params(top='off', bottom='off', left='off', right='off', labelleft='off', labelbottom='on')
import matplotlib.pyplot as pltimport random
prefix =6.18
rx =[prefix+(0.001*random.random())for i in arange(100)]
ry =[prefix+(0.001*random.random())for i in arange(100)]
plt.plot(rx,ry,'ko')
frame1 = plt.gca()for xlabel_i in frame1.axes.get_xticklabels():
xlabel_i.set_visible(False)
xlabel_i.set_fontsize(0.0)for xlabel_i in frame1.axes.get_yticklabels():
xlabel_i.set_fontsize(0.0)
xlabel_i.set_visible(False)for tick in frame1.axes.get_xticklines():
tick.set_visible(False)for tick in frame1.axes.get_yticklines():
tick.set_visible(False)
plt.show()
I’m trying to plot a figure without tickmarks or numbers on either of the axes (I use axes in the traditional sense, not the matplotlib nomenclature!). An issue I have come across is where matplotlib adjusts the x(y)ticklabels by subtracting a value N, then adds N at the end of the axis.
This may be vague, but the following simplified example highlights the issue, with ‘6.18’ being the offending value of N:
import matplotlib.pyplot as plt
import random
prefix = 6.18
rx = [prefix+(0.001*random.random()) for i in arange(100)]
ry = [prefix+(0.001*random.random()) for i in arange(100)]
plt.plot(rx,ry,'ko')
frame1 = plt.gca()
for xlabel_i in frame1.axes.get_xticklabels():
xlabel_i.set_visible(False)
xlabel_i.set_fontsize(0.0)
for xlabel_i in frame1.axes.get_yticklabels():
xlabel_i.set_fontsize(0.0)
xlabel_i.set_visible(False)
for tick in frame1.axes.get_xticklines():
tick.set_visible(False)
for tick in frame1.axes.get_yticklines():
tick.set_visible(False)
plt.show()
The three things I would like to know are:
How to turn off this behaviour in the first place (although in most cases it is useful, it is not always!) I have looked through matplotlib.axis.XAxis and cannot find anything appropriate
How can I make N disappear (i.e. X.set_visible(False))
Is there a better way to do the above anyway? My final plot would be 4×4 subplots in a figure, if that is relevant.
I was not actually able to render an image without borders or axis data based on any of the code snippets here (even the one accepted at the answer). After digging through some API documentation, I landed on this code to render my image
I used the tick_params call to basically shut down any extra information that might be rendered and I have a perfect graph in my output file.
回答 5
我已经对该图进行了颜色编码以简化此过程。
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
您可以使用以下命令完全控制图形,以完成答案,我还添加了对样条线的控制:
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)# X AXIS -BORDER
ax.spines['bottom'].set_visible(False)# BLUE
ax.set_xticklabels([])# RED
ax.set_xticks([])# RED AND BLUE TOGETHER
ax.axes.get_xaxis().set_visible(False)# Y AXIS -BORDER
ax.spines['left'].set_visible(False)# YELLOW
ax.set_yticklabels([])# GREEN
ax.set_yticks([])# YELLOW AND GREEN TOGHETHER
ax.axes.get_yaxis().set_visible(False)
I’ve colour coded this figure to ease the process.
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
You can have full control over the figure using these commands, to complete the answer I’ve add also the control over the splines:
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# X AXIS -BORDER
ax.spines['bottom'].set_visible(False)
# BLUE
ax.set_xticklabels([])
# RED
ax.set_xticks([])
# RED AND BLUE TOGETHER
ax.axes.get_xaxis().set_visible(False)
# Y AXIS -BORDER
ax.spines['left'].set_visible(False)
# YELLOW
ax.set_yticklabels([])
# GREEN
ax.set_yticks([])
# YELLOW AND GREEN TOGHETHER
ax.axes.get_yaxis().set_visible(False)
When using the object oriented API, the Axes object has two useful methods for removing the axis text, set_xticklabels() and set_xticks().
Say you create a plot using
fig, ax = plt.subplots(1)
ax.plot(x, y)
If you simply want to remove the tick labels, you could use
ax.set_xticklabels([])
or to remove the ticks completely, you could use
ax.set_xticks([])
These methods are useful for specifying exactly where you want the ticks and how you want them labeled. Passing an empty list results in no ticks, or no labels, respectively.
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.