Matplotlib: remove warning about matplotlib.use() - python

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.

Related

Name re is not defined although re is imported in module and in main code

I'm working on a Jupyter Notebook for my master's thesis and I'd like to keep it clean. I use a lot of functions to assign categories to groups of data.
Therefore, I've decided to put all those functions in a functions.py module which I import at the start of my notebook. My notebook has the following imports:
import sys
sys.path.append('../src/') # ugly hack to be able to import the functions module
import re
import numpy as np
import pandas as pd
import seaborn as sns
import functions as fn
One of my functions uses the "re" module for matching strings with regex. When I called the said function I get NameError: ("name 're' is not defined", 'occurred at index 0') so I figured I had to import re at the beginning of my functions.py file. This didn't change anything. So I even tried to put import re in the function body, but it wouldn't work either.
I have absolutely no idea why re doesn't work despite trying to import it everywhere.
Note: my functions worked correctly when I was defining and using them from the notebook so I know for certain it's not a bug in my function.
Solved my own issue, the answer is stupidly simple: Jupyter doesn't take into account any edits to an imported module even if you reimport it. If you make any changes to a module you have to shut down the kernel and restart it, import again and the edits will work.
In my particular case I had added import re to my functions.py but Jupyter didn't take it into account until I restarted the kernel.
In a notebook, you can use the importlib library and call importlib.reload(module) instead of restarting the kernel

What's the purpose of the file "pylab.py"

I looked at the file "pylab.py" at matplotlab's directory and found that it contains a great bunch of imports, and then defines a single variable "bytes" at the last line. Here is the last several lines of this file:
from numpy.fft import *
from numpy.raenter code herendom import *
from numpy.linalg import *
import numpy as np
import numpy.ma as ma
# don't let numpy's datetime hide stdlib
import datetime
# This is needed, or bytes will be numpy.random.bytes from
# "from numpy.random import *" above
bytes = six.moves.builtins.bytes
I wonder what's the purpose of such a file when it only defines a seemingly useless variable. As a result, what's the purpose of writing code like from matplotlib import pylab?
The matplotlib docs say:
pylab is a convenience module that bulk imports matplotlib.pyplot (for plotting) and numpy (for mathematics and working with arrays) in a single name space. Although many examples use pylab, it is no longer recommended.
So for example, you can do
>>> from pylab import *
And you have imported all the names imported by pylab into your local namespace. This is convenient when using the interactive shell.
Additionally, pylab imports datetime and bytes. This is because the from numpy.foo import * statements import numpy objects named bytes and datetime which are not the same as the standard python objects with these names, so they need to be overridden with the standard versions.
The practice of importing names into a module just so other modules can import them from there instead of the original module is not unusual. For example, given this module:
$ cat foo/__init__.py
from bar import *
from baz.quux import *
from spam import eggs
Other modules can do from foo import eggs rather than from foo.spam import eggs. Apart from the convenience of less typing, this approach hides the internal structure of the foo package from its clients. As long as they import from the top level module they need not be concerned that the internal structure of the package may change over time. This is a form of the facade design pattern.

How to share imports between modules?

My package looks like this:
These helpers, since they are all dealing with scipy, all have common imports:
from matplotlib import pyplot as plt
import numpy as np
I'm wondering if it is possible to extract them out, and put it somewhere else, so I can reduce the duplicate code within each module?
You can create a file called my_imports.py which does all your imports and makes them available as * via the __all__ variable (note that the module names are declared as strings):
File my_imports.py:
import os, shutil
__all__ = ['os', 'shutil']
File your_other_file.py:
from my_imports import *
print(os.curdir)
Although you might want to be explicit in your other files:
File your_other_file.py:
from my_imports import os # or whichever you actually need.
print(os.curdir)
Still, this saves you having to specify the various sources each time — and can be done with a one-liner.
Alright, here is my tweak,
Create a gemfile under the package dir, like this
import numpy as np
from matplotlib import pyplot as plt
import matplotlib as mpl
Then, for other files, like app_helper.py
from .gemfile import *
This comes from here Can I use __init__.py to define global variables?

Issues with Importing Modules into Python

new to Python programming and have encountered an issue importing modules.
I have a main application (compare.py) with imports as follows :
# import the necessary packages
from skimage.measure import structural_similarity as ssim
import matplotlib.pyplot as plt
import numpy as np
import os
import skimage
from skimage import io
from skimage import color
from epilib import mse
from epilib import compare_images
and I have defined two functions in epilib, one called mse() and one called compare_images().
The code in mse() requires numpy. When I execute 'python compare.py', I get the following error message :
File "C:\Users\Dan\epilib.py", line 7, in mse err = np.sum((imageA.astype("float") - imageB.astype("float")) ** 2)
NameError: name 'np' is not defined
I assumed that because 'import numpy as np' was executed prior to import epilib, that the numpy library would be available to epilib? When I added 'import numpy as np' to the top of epilib, the issue resolved.
I don't see it as very efficient to have to move all the import statements to epilib. I was hoping to have epilib as just a library of functions and I could import into various python programs as required.
Is there a way to accomplish this?
That is not how python works, if you want to use numpy library in a module (in this case in eplib module), you need to import it in that module as well, eplib would get not the numpy module imported in your compare.py .
You should import numpy in eplib.py as -
import numpy as np
I do not think there would be any issue in efficiency, since once python imports a module for the first time, it caches the module in sys.modules , so whenever you re-import it (even if its in a different module) as long as its the same python process , Python would not re-import it, instead it would return the module object from sys.modules .

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'])

Categories