Matplotlib: check if undefined DISPLAY - python

Sometimes I run my script via ssh. This answer told me to set up
import matplotlib
#matplotlib.use('Agg') # Must be before importing matplotlib.pyplot or pylab!
import matplotlib.pyplot as plt
when I get the undefined SCREEN error by running the script via ssh. However with that preamble I cannot view the graphs interactively when I run the script on my local machine.
What's the condition to check if the screen is defined? I'd like to do
if SCREEN == None:
matplotlib.use('Agg')
How's the proper code for that, how can I check this?

It looks like an easiest way to do this is to check 'DISPLAY' environment variable
import os
# 'DISPLAY' will be something like this ':0'
# on your local machine, and None otherwise
if os.environ.get('DISPLAY') is None:
matplotlib.use('Agg')

Related

Is there a way to automatically switch matplotlib backend in Jupyter?

When working with my python package, a certain function has some interactive matplotlib stuff going on.
In Jupyter Notebook I always have to use the magic %matplotlib qt to switch backend in order to make it work.
However, this might seem obvious to me, but others who're trying to work with my package this is not that straight forward.
This is what I have so far in my __init__.py:
def run_from_notebook():
return hasattr(__builtins__, '__IPYTHON__')
if run_from_notebook():
# this has no effect
try:
from IPython import get_ipython
ipython = get_ipython()
except ImportError:
import IPython.ipapi
ipython = IPython.ipapi.get()
ipython.magic("matplotlib qt")
I also tried:
if matplotlib.get_backend() != 'Qt5Agg':
matplotlib.use('Qt5Agg')
but still no effect.
Is there a way to automatically switch backend in Jupyter Notebook when someone imports my package?
and also: Is there any reason it's not considered as a good practice?
It turns out that the problem is with the run_from_notebook function. When running it simply in a notebook cell it returns True, but when it's imported from my module, it returns False. The question now is rather: How to detect if code is run inside Jupyter?
For example running manually
def switch_backend_to_Qt5():
import matplotlib
if matplotlib.get_backend() != 'Qt5Agg':
matplotlib.use('Qt5Agg')
gets the job done.
EDIT :
The following function suits my needs:
import os
def run_from_notebook():
try:
__IPYTHON__
# If it's run inside Spyder we don't need to do anything
if any('SPYDER' in name for name in os.environ):
return False
# else it's probably necessary to switch backend
return True
except NameError:
return False

Why do imports work only when running without run configuration?

In PyCharm, I have one common module (called common.py) that I want to import from a few other files. It used to be working fine, until recently when I ran the program using Ctrl+Enter. Since then, I can now only run the code with Ctrl+Enter, using the normal run configuration doesn't recognize the imports; it says "unused import" and doesn't resolve references to methods in common.py. Here is the code in the file I'm trying to run:
from matplotlib import pyplot as plt
from matplotlib import colors as cl
from common import *
N = np.arange(5, 30, 1, int)
get_noiseless_eigenvalues(np.matrix([[1]]))
Both np and get_noiseless_eigenvalues aren't resolved by PyCharm, even though they are both present in common.py:
import numpy as np
def get_noiseless_eigenvalues(m: np.matrix):
return [v for v in np.linalg.eigh(m)[1] if sum(v) == 0]
I checked that the directory is indeed still marked as Sources Root. What could be the problem here?
Edit: I checked the changes with git, turns out that an empty __init__.py was added in two locations; for now, I can at least run the program normally but I'm still wondering why this happened

Why doesn't '%matplotlib inline' work in python script?

The following does not work:
However this totally works in Jupiter Notebook.
If I simply comment it out, the graph doesn't show up. (Maybe it won't show up anyways)
import pandas as pd
import matplotlib
from numpy.random import randn
import numpy as np
import matplotlib.pyplot as plt
df = pd.read_csv('data/playgolf.csv', delimiter='|' )
print(df.head())
hs = df.hist(['Temperature','Humidity'], bins=5)
print(hs)
Other answers and comments have sufficiently detailed why %matplotlib inline cannot work in python scripts.
To solve the actual problem, which is to show the plot in a script, the answer is to use
plt.show()
at the end of the script.
If you are using notebook and run my_file.py file as a module
Change the line "%matplotlib inline" to "get_ipython().run_line_magic('matplotlib', 'inline')".
Then run my_file.py using this %run
It should look like this:
In my_file.py:
get_ipython().run_line_magic('matplotlib', 'inline')
In notebook:
%run my_file.py
This run my_file.py in ipython, which help avoid the bug
NameError: name 'get_ipython' is not defined
According to http://ipython.readthedocs.io/en/stable/interactive/magics.html, % is a special iPython/Jupyter command:
Define an alias for a system command.
%alias alias_name cmd defines alias_name as an alias for cmd
In standard Python, % takes the remainder when one number is divided by another (or can be used for string interpolation), so in a standard Python program, %matplotlib inline doesn't make any sense. It does, however, work in iPython, as described above.

Conditional import in a module

I have created a module modA which I am importing in my main program. Depending on what happens in my main program (it has an interactive mode and a batch script mode), I want modA itself to import matplotlib with either the TkAgg backend or the ps backend. Is there a way for my main program to communicate information to modA to tell it how it should import matplotlib?
To clarify the situation:
The main program:
#if we are in interactive mode
#import modA which imports matplotlib using TkAgg backend
#else
#import modA which imports matplotlib using the ps backend
Module modA:
#import matplotlib
#matplotlib.use('ps') or matplotlib.use('TkAgg') (how can I do this?)
Have a function in your module which will determine this.
import matplotlib
def setEnv(env):
matplotlib.use(env)
Then in your program you can have modA.setEnv('ps') or something else based on if-else statement condition.
You do not need a conditional import here (since you are using only one external module), but it is possible to do it:
if condition:
import matplotlib as mlib
else:
import modifiedmatplotlib as mlib
For more information about importing modules within function see these:
Python: how to make global imports from a function
Is it possible to import to the global scope from inside a function (Python)?
You can probably detect the way your session is started by evaluating the arguments passed to the command line:
import sys
import matplotlib
if '-i' in sys.argv:
# program started with an interactive session
matplotlib.use('TkAdd')
else:
# batch session
matplotlib.use('ps')
If not, you can use os.environ to communicate between modules:
In main:
import os
if interactive:
os.environ['MATPLOTLIB_USE'] = 'TkAdd'
else:
os.environ['MATPLOTLIB_USE'] = 'ps'
In modA:
import os
import matplotlib
matplotlib.use(os.environ['MATPLOTLIB_USE'])

Matplotlib: remove warning about matplotlib.use()

In a Python module where I use matplotlib, I want to make sure it works also when I run the script on a remote machine via ssh. So I do:
import matplotlib
matplotlib.use('Agg')
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import numpy as np
import pylab
import scipy.stats
import scipy.stats.mstats
It works. Too bad that when I run it directly on a machine (not a remote one!), it gives me the following warning:
This call to matplotlib.use() has no effect because the the backend
has already been chosen; matplotlib.use() must be called before
pylab, matplotlib.pyplot, or matplotlib.backends is imported for the
first time.
How do I remove this message?
While I can't test this Ipython tells me that "one can set warn=False to supporess the warnings."
Source:
matplotlib.use?
Type: function
String Form:<function use at 0x98da02c>
File: /usr/lib/pymodules/python2.7/matplotlib/__init__.py
Definition: matplotlib.use(arg, warn=True)
Docstring:
Set the matplotlib backend to one of the known backends.
The argument is case-insensitive. For the Cairo backend,
the argument can have an extension to indicate the type of
output. Example:
use('cairo.pdf')
will specify a default of pdf output generated by Cairo.
.. note::
This function must be called *before* importing pyplot for
the first time; or, if you are not using pyplot, it must be called
before importing matplotlib.backends. If warn is True, a warning
is issued if you try and call this after pylab or pyplot have been
loaded. In certain black magic use cases, e.g.
:func:`pyplot.switch_backends`, we are doing the reloading necessary to
make the backend switch work (in some cases, e.g. pure image
backends) so one can set warn=False to supporess the warnings.
To find out which backend is currently set, see
:func:`matplotlib.get_backend`.
Always fun to find a typo in the docs.
Warning messages are usually significant, and I recommend not ignoring. I found your question while searching for a solution to my doc build with sphinx. I received a similar message, and some additional context for the warning:
UserWarning:
This call to matplotlib.use() has no effect because the backend has already
been chosen; matplotlib.use() must be called before pylab, matplotlib.pyplot,
or matplotlib.backends is imported for the first time.
The backend was originally set to 'Qt5Agg' by the following code:
File "setup.py", line 131, in <module>
'psql' : ['psycopg2>=2.7.1'],
I then found a solution at https://github.com/conchoecia/pauvre/issues/18 . With the import order as follows:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
Before the fix I only had the following import for the module
from mymod.utils import plotutils
import mymod.plots as plots
import matplotlib.pyplot as plt
I am thinking the import order for this question resulted in the warning message. However, I was not able to recreate your warning for the information provided. It would have been nice to see a couple more lines from that warning.
After some more discussions with other developers, it became apparent my import of pyplot was in the file whereas it belongs in the module just where I need to use plt.
Understanding the render is important, and you can get more at
https://matplotlib.org/faq/usage_faq.html#what-is-a-backend
and
https://matplotlib.org/api/matplotlib_configuration_api.html#matplotlib.use
Just remember other proceeding code may be changing or defaulting the backend names.

Categories