I'm generating matplotlib figures in a script which I run alternatively with or without a graphical display. I'd like the script to adjust automatically: with display, it should show the figures interactively, while without a display, it should just save them into a file.
From an answer to the question Generating matplotlib graphs without a running X server, I learnt that one can use the Agg backend for non-interactive plotting.
So I am trying with this code:
import matplotlib
try:
import matplotlib.pyplot as plt
fig = plt.figure()
havedisplay = True
except:
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig = plt.figure()
havedisplay = False
# do the plotting
if havedisplay:
plt.show()
else:
fig.savefig("myfig.png")
This works as excepted in the case with a display. However, without a display, the call to matplotlib.use is not effective, since the display has already been chosen. It's clear that I should call matplotlib.use before import matplotlib.pyplot, but then I don't know how to test whether a display is available or not.
I have also tried with the experimental function matplotlib.switch_backend instead of matplotlib.use, but this generates a RuntimeError.
Does someone have an idea how to make the above code work as intended, or can suggest an alternative way to detect whether a display is available for matplotlib or not?
You can detect directly if you have a display with the OS module in python.
in my case it's
>>> import os
>>> os.environ["DISPLAY"]
':0.0'
The code below works for me in Linux and Windows (where it assumes there is a display device):
import os
import matplotlib
if os.name == 'posix' and "DISPLAY" not in os.environ:
matplotlib.use('Agg')
See https://stackoverflow.com/a/1325587/896111.
Note that the line matplotlib.use('Agg') must appear after the first import of matplotlib (otherwise you will get an error).
try this?
import matplotlib,os
r = os.system('python -c "import matplotlib.pyplot as plt;plt.figure()"')
if r != 0:
matplotlib.use('Agg')
import matplotlib.pyplot as plt
fig = plt.figure()
fig.savefig('myfig.png')
else:
import matplotlib.pyplot as plt
fig = plt.figure()
plt.show()
By combining both of the approaches above, you'll get perhaps the best solution:
havedisplay = "DISPLAY" in os.environ
if not havedisplay:
exitval = os.system('python -c "import matplotlib.pyplot as plt; plt.figure()"')
havedisplay = (exitval == 0)
The reason for this combo is that the run time of the os.system command may take a while. So when you are sure you have the display (judging by the os.environ value), you can save that time.
On the other hand, even if the DISPLAY key is not set in the os.environ variable, there is still a chance that the plotting methods will work with the graphical interface (e.g. when using Windows command line).
when use GUI backend the figure object has show() method, you can use it to do the switch:
import matplotlib
#matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig = plt.figure()
havedisplay = False
if hasattr(fig, "show"):
plt.show()
else:
print "save fig"
fig.savefig("myfig.png")
The solution offered by #Oz123 generated a syntax error for me. However, i was able to easily detect the display using:
import os
havedisplay = "DISPLAY" in os.environ
#plotting...
That was the simplest thing i could find, anyway.
import os
have_display = bool(os.environ.get('DISPLAY', None))
have_display is False if DISPLAY is not in the environment or is an empty string. otherwise, it's True
Related
I work with matplotlib. When I add the following lines, the figure is not displayed.
import matplotlib
matplotlib.use('Agg')
here is my code :
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plot
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig = plot.figure(figsize=(12,9))
def convert_sin_cos(x):
fft_axes = fig.add_subplot(331)
y = np.cos(x)
fft_axes.plot(x,y,'g*')
for i in range(3):
fft_axes = fig.add_subplot(332)
x=np.linspace(0,10,100)
fft_axes.plot(x,i*np.sin(x),'r+')
plot.pause(0.1)
convert_sin_cos(x)
Thanks
That's the idea!
When I run your code, the console says:
matplotlibAgg.py:15: UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.
How can it be useful? When you're running matplotlib code in a terminal with no windowing system, for example: a cluster (running the same code with different inputs, getting lot of results and without the need to move the data I can plot whatever I need).
Currently, I am attempting to follow along with a Sentdex YouTube tutorial video (https://www.youtube.com/watchv=cExOVprMlQg&list=PLQVvvaa0QuDe6ZBtkCNWNUbdaBo2vA4RO), however I am running into some difficulties with plt.show(). I have written this script nearly verbatim as detailed in this video and I have turned to StackOverflow to update any syntax, yet I have not been able to actually view this graph. Nothing comes up when I run the script, the shell just spits out '>>'. I have changed backends, unistalled, upgraded and reinstalled matplotlib. I've also tried this script on the exact version of Python seen in this video as well as 3.6.1 and a few others on OS X and Windows 10 via Parallels - still running into the same issue.
Here is my code thus far:
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import matplotlib.dates as mdates
import numpy as np
import pylab
def graphRawFX():
date, bid, ask = np.loadtext('GBPUSD1d.txt', unpack=True,
delimiter='-',
converters={0: mdates.strpdate2numb('%Y%m%d%H%M%S')})
fig = plt.figure(figsize=(10,7))
ax1 = plt.subplot2grid((40,40), (0), rowspan=40, colspan=40)
ax1.plot(date, bid)
ax1.plot(date, ask)
ax1.xaxis.set_major_formatter(mdate.DateFormatter('%Y-%m-%d %H:#M:#S'))
for label in ax1.axis,get_xticklabels():
label.set_rotation(45)
ply.gca().get_yaxis().get_major_formatter().set_useOffset(False)
plt.grid(True)
plt.show()
pylab.show()
Any thoughts on a solution?
You defined a function, which plots. But you never call the function! Your script is empty from python's perspective.
Add graphRawFX() at the end, without any indentation to actually call the function.
If this code is by any means incomplete and not your issue, check your install and clean up the code. The whole import pylab thing looks unwanted. Also ply does not exist and so on. Start with the basics, the official examples and the docs, not with some yt-video which uses tons of (advanced) stuff.
I have it working (mac OS). Just try to copy paste to see if there's some typing problem. (it was working without "import pylab" and the "pylab.show()" I have just put it to have the same code you have.
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker as mticher
import matplotlib.dates as mdates
import numpy as np
import pylab
def graphRawFX():
date,bid,ask = np.loadtxt('GBPUSD1d.txt', unpack=True, delimiter=',',converters={0:mdates.strpdate2num('%Y%m%d%H%M%S')})
fig = plt.figure(figsize=(10,7))
ax1 = plt.subplot2grid((40,40), (0,0), rowspan=40, colspan=40)
ax1.plot(date,bid)
ax1.plot(date,ask)
plt.gca().get_yaxis().get_major_formatter().set_useOffset(False)
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M:%S'))
for label in ax1.xaxis.get_ticklabels() :
label.set_rotation(45)
ax1_2=ax1.twinx()
ax1_2.fill_between(date,0, (ask-bid),facecolor='g',alpha=.3)
plt.subplots_adjust(bottom=.23)
plt.grid(True)
plt.show()
pylab.show()
graphRawFX()
I followed the setting from here to make matplotlib/seaborn available to display in Zeppelin. However, with the following code:
%python
import seaborn as sns
import matplotlib
import numpy as np
matplotlib.use('Agg')
import matplotlib.pyplot as plt
plt.rcdefaults()
import StringIO
def show(p):
img = StringIO.StringIO()
p.savefig(img, format='svg')
img.seek(0)
print "%html <div style='width:600px'>" + img.buf + "</div>"
""" Prepare your plot here ... """
# Use the custom show function instead of plt.show()
x = np.random.randn(100)
ax = sns.distplot(x)
show(sns.plt)
It is strange that the displayed figure show the desired lightblue color the first time I run the code but will display different colors if I execute the same piece of code. Is there a way to force seaborn to keep constant color being displayed? Thanks.
It's not entirely clear what is meant by "running a second time".
However you may try to actually close the figure before running it again. E.g.
plt.close("all")
in order to make sure, a new figure is created which should have the same default color every time.
I have a simple script to test a plot in matplotlib but no window showing the figure appears. On reading other questions on stackoverflow, I've done the following to resolve this:
installed PySide using these instructions.
edited matplotlibrc file with these two lines:
backend : Qt4Agg
#backend.qt4 : PySide # PyQt4 | PySide
so that the command python -c 'import matplotlib; import matplotlib.pyplot; print(matplotlib.backends.backend)' now yields Qt4Agg whereas before it gave agg
included the pylab.show() command. So the set of commands that I now tried in the python interpreter after installing Pyside, and editing the matplotlibrc file look like this:
import pylab
pylab.ion()
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0,5,0.1)
y = np.sin(x)
plt.plot(x,y)
[<matplotlib.lines.Line2D object at 0x7fcef627cdd0>]
pylab.show()
However, the plot still doesn't show. Could anyone please help me with this? I am using Ubuntu 14.04 in VirtualBox with python2.7.
When I use your code the plot actually flashes on the screen, but closes immediately. Placing an input() function at the end might help you with debugging it:
import pylab
import matplotlib.pyplot as plt
import numpy as np
pylab.ion()
x = np.arange(0,5,0.1)
y = np.sin(x)
plt.plot(x,y)
pylab.show()
tin = input("Test Input: ")
And removing the pylab.ion() actually keep the plot on the screen. This gives you another hint. There are already some good answers why this is happening. E.g.:
Matplotlib ion() function fails to be interactive
In the past I was able to do simple animations with matplotlib with a for loop, but this hasn't worked for some time now.
The standard answer is that you have to turn interactive mode on and/or force a redraw with matplotlib.pyplot.draw(). Here is my minimal working example:
import numpy as np
import matplotlib
matplotlib.use('Qt4Agg')
import matplotlib.pyplot as mplot
mplot.ion()
fig = mplot.figure(1)
ax = fig.add_subplot(111)
for ii in np.arange(0,10):
x = 200*np.random.rand(30)
ax.plot(x)
mplot.draw()
filename = ("img_%d.png" % ii)
mplot.savefig(filename)
When I run this in Interactive Python Editor, I get one figure at the very end with all the plots in it (this also happens with mplot.show())
When I run this in IPython 3.1 (with Python 3.3.5) from the command line, I get nothing at all.
The mplot.savefig(filename) line does seem to work, as the images are generated.
(It's possible this is a bug in the Qt4 backend.)
Try deleting the line matplotlib.use('Qt4Agg'). Works for me. Also works with matplotlib.use('TkAgg'). So it is a backend problem. There is another way to do animations.