I wrote the solution implemented in the hope that it serves at someone else.
···
=========
I wrote a script using basemap and matplolib. which draw a map.Dread a
file containing a bunch of Genbank accession numbers, and downloaded
the Genbank records:
....
from pylab import *
import os, sys
import os.path
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
map = Basemap(projection='cyl', resolution='l')
map.drawcoastlines()
map.drawmapboundary()
...
This worked fine as a script, but when I attempted to turn it into a
Windows executable with py2exe and the setup.py script:
"""
from distutils.core import setup
import py2exe
from distutils.core import setup
import py2exe
import glob
import matplotlib
opts = {
'py2exe': { "includes" : ["sip", "PyQt4", "matplotlib.backends",
"matplotlib.backends.backend_qt4agg",
"matplotlib.figure","pylab", "numpy",
"matplotlib.numerix.fft","mpl_toolkits.basemap",
"matplotlib.numerix.linear_algebra",
"matplotlib.numerix.random_array",
"matplotlib.backends.backend_tkagg"],
# 'excludes': ['_gtkagg', '_tkagg','_agg2','_cairo',
'_cocoaagg', '_fltkagg', '_gtk', '_gtkcairo', ],
'dll_excludes': ['libgdk-win32-2.0-0.dll',
'libgobject-2.0-0.dll']
}
}
data_files = [(r'mpl-data',
glob.glob(r'C:\Python25\Lib\site-packages\matplotlib\mpl-data\*.*')),
# Because matplotlibrc does not have an extension,
glob does not find it (at least I think that's why)
# So add it manually here:
(r'mpl-data',
[r'C:\Python25\Lib\site-packages\matplotlib\mpl-data\matplotlibrc']),
(r'mpl-data\images',glob.glob(r'C:\Python25\Lib\site-packages\matplotlib\mpl-data\images\*.*')),
(r'mpl-data\fonts',glob.glob(r'C:\Python25\Lib\site-packages\matplotlib\mpl-data\fonts\*.*'))]
setup(windows=[{"script" : "myapp.py",
"icon_resources": [(1, "myapp.ico")]}, ],
version = "1.0",
options=opts, data_files=data_files)
with the command python setup.py py2exe, attempting to run the
resulting myapp.exe would throw an error.
The Error
This is the error thrown on running the executable:
Traceback (most recent call last)
File "myapp.py", line 40, in <module>
File "mpl_toolkits\basemap\__init__.pyc", line 774, in __init__
File "mpl_toolkits\basemap\__init__.pyc", line 848, in _readboundarydata
IOError: Unable to open boundary dataset file. Only the 'crude', 'low',
'intermediate' and 'high' resolution datasets are installed by default.
If you are requesting a 'full' resolution dataset, you may need to
download and install those files separately
(see the basemap README for details).
The Problem
Location of basemap data
The problem is identified when basemap is imported, the code of
basemap/__init__.py try to establish the basemap data directory in the
library.zip file.
[install dir]\dist\library.zip\mpl_toolkits\basemap\data
Under normal script-like execution, it works, the path is a string
indicating a location accessible through the filesystem . However with
py2exe, the location of data basemap directory is located within the
shared zip archive that py2exe creates and the above error is thrown.
The Solution
The solution came in three times
1. Add mpl_toolkits.basemap in the option list (setup.py)
#--------------------------------------------
opts = {
'py2exe': { "includes" : ["sip", "PyQt4", "matplotlib.backends",
"matplotlib.backends.backend_qt4agg",
"matplotlib.figure","pylab", "numpy",
"matplotlib.numerix.fft","mpl_toolkits.basemap",
"matplotlib.numerix.linear_algebra",
"matplotlib.numerix.random_array",
"matplotlib.backends.backend_tkagg"],
#--------------------------------------------
2. Add basemap\data in data_files list
#--------------------------------------------
data_files = [(r'mpl-data',
glob.glob(r'C:\Python25\Lib\site-packages\matplotlib\mpl-data\*.*')),
(r'mpl-data',
[r'C:\Python25\Lib\site-packages\matplotlib\mpl-data\matplotlibrc']),
(r'mpl-data\images',glob.glob(r'C:\Python25\Lib\site-packages\matplotlib\mpl-data\images\*.*')),
(r'mpl-data\data',glob.glob(r'C:\Python25\Lib\site-packages\mpl_toolkits\basemap\data\*.*')),
#---------------------------------------------
3. Modification of
C:\Python25\Lib\site-packages\mpl_toolkits\basemap\__init__.py
Near l.50, add the block "check if it turns into a Windows executable
with py2exe"
if 'BASEMAPDATA' in os.environ:
basemap_datadir = os.environ['BASEMAPDATA']
if not os.path.isdir(basemap_datadir):
raise RuntimeError('Path in environment BASEMAPDATA not a directory')
else:
basemap_datadir = os.sep.join([os.path.dirname(__file__), 'data'])
#-----------------------------------------------
# Check if it turns into a Windows executable with py2exe
import re
if (basemap_datadir.find("library.zip") > -1):
basemap_datadir=re.sub("library.zip","",basemap_datadir)
basemap_datadir=re.sub("mpl_toolkits","mpl-data",basemap_datadir)
basemap_datadir=re.sub("basemap","",basemap_datadir)
#-----------------------------------------------
This works under normal script execution and in py2exe mode.