Home > py2exe > py2exe: matplotlib

py2exe: matplotlib

5 Luglio 2011

Avendo a che fare con matplotlib, ho avuto parecchi problemi a configurare il setup di py2exe.
Grazie alla doc ufficiale di py2exe con qualche piccolo accorgimento, sono
riuscito a fare il freeze della mia applicazione.

Riassumo il tutto estrapolando solo la parte inerente Matplotlib:

'''Module for HistoGram creation'''

import numpy as np
import matplotlib
matplotlib.use('wxagg') # backend

import matplotlib.pyplot as plt


class Bars(object):
    '''Crea un istogramma in base ai dati in ingresso:
           possono essere di tipo dict(nome: valore) o
           di tipo list, con il formato tipico
           del metodo fetchall() d sqlite3
    ''' 

    def __init__(self, data):
        self.data = data
        self.dict_data = {}
        print "HISTO > Loading data... ", self.data
        for item in self.data:
            self.dict_data[item[0]] = (item[1])
        try:
            n_bars = len(self.dict_data)
            pts = self.dict_data.values()
            teams = self.dict_data.keys()
            ind = np.arange(n_bars)     # the x locations for bar
            width = 0.2                 # the width of the bars
            plt.subplot(111)
            
            bars = plt.bar(ind + 0.2, pts, width, color='b', align = 'center')
            
            plt.title('Classifica')
            plt.ylabel('pts')
            plt.xticks(ind + width , teams, size = 'x-small', rotation = 15)
            
            for vbar in bars:
                val = float(vbar.get_height())
                x_pos = vbar.get_x() + 0.4
                y_pos = vbar.get_height() - 0.1 * vbar.get_height()
                plt.text(x_pos, y_pos, '%.1f'%val, ha='center', va='bottom',
                         size = 'small', rotation = 90)
            plt.show()
        
        except AttributeError:
            print "Grafico non rappresentabile, controllare dato in ingresso"

def main():
    '''app starter'''
    data = [('Boy SAN', 100), ('Cioppersson', 105),
            ('Stella Blu Kativeria', 120), ('Pippo', 180),
            ('MiddleSboron', 98), ('Nizzi', 140), ('F.C.Zipangolo', 165),
            ('Real Ancona', 135), ('Gnagna', 88), ('Cento', 98)]
    Bars(data)
if __name__ == '__main__':
    main()

Dal solito sample del setup di py2exe:

#!/usr/bin/python
"""py2exe custom setup Sample
author: bancaldo"""

import py2exe, sys, wx, os, glob
import matplotlib
from distutils.core import setup

if len(sys.argv) == 1:
    sys.argv.append("py2exe")
    sys.argv.append("-q")

class FileBrowser(wx.FileDialog):
    '''Class for file browser'''
    def __init__(self):
        self.fin = None
        wildcard = "File di testo (*.py)|*.py|" \
            "Tutti i files (*.*)|*.*"
        wx.FileDialog.__init__(self, None, "scegli il file", os.getcwd(),
                               "", wildcard, wx.OPEN | wx.CHANGE_DIR)
        if self.ShowModal() == wx.ID_OK:  
            print(self.GetPath())
            self.file = self.GetPath()
            self.fin = open(self.file, 'r')
        else:
            print "operazione apertura annullata"
            self.Destroy()
        self.Destroy()

class Target(object):
    '''Terget'''
    def __init__(self, **kw):
        self.__dict__.update(kw)
        # info di versione
        self.version = "1.0.0"
        self.company_name = "Bancaldo TM"
        self.copyright = "no copyright"
        self.name = "py2exe sample files"


def main():
    '''py2exe setup starter'''
    app = wx.PySimpleApp()
    app.MainLoop()

    manifest_template = '''
    <?xml version='1.0' encoding='UTF-8' standalone='yes'?>
    <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
      <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
          <requestedPrivileges>
            <requestedExecutionLevel level='asInvoker' uiAccess='false' />
          </requestedPrivileges>
        </security>
      </trustInfo>
      <dependency>
        <dependentAssembly>
          <assemblyIdentity 
    	 type='win32' 
    	 name='Microsoft.VC90.CRT' 
    	 version='9.0.21022.8' 
    	 processorArchitecture='*' 
    	 publicKeyToken='1fc8b3b9a1e18e3b' />
        </dependentAssembly>
      </dependency>
      <dependency>
        <dependentAssembly>
          <assemblyIdentity
             type="win32"
             name="Microsoft.Windows.Common-Controls"
             version="6.0.0.0"
             processorArchitecture="*"
             publicKeyToken="6595b64144ccf1df"
             language="*" />
        </dependentAssembly>
      </dependency>
    </assembly>
    '''
    file_to_freeze = FileBrowser().file

    textentry = wx.TextEntryDialog(None, "nome file EXE?", '', '')
    if textentry.ShowModal() == wx.ID_OK:
        destname = textentry.GetValue()
    
    rt_manifest = 24
    
    explicit_incl = ["sqlalchemy.dialects.sqlite.base",
                     "matplotlib.backends.backend_wxagg",]
    other_res = [(rt_manifest, 1, manifest_template % dict(prog = "Fanta"))]

    setup_opts = {"py2exe": {"includes": explicit_incl,
                             "compressed": 1,
                             "optimize": 2,
                             #"ascii": 1,
                             "bundle_files": 1,}}
    
    test_wx = Target(description = "A GUI app",
                     script = file_to_freeze,
                     other_resources = other_res,
                     icon_resources = [(1, "images\\py.ico")],
                     dest_base = destname)

    # images    
    path = (os.getcwd() + "\\images\\")
    data_files = [('images', [png for png in glob.glob(path + '*.png')])]
    # matplotlib
    data_files.extend(matplotlib.get_py2exe_datafiles())

    setup(data_files = data_files, # images
          options = setup_opts,
          zipfile = None,
          windows = [test_wx],
        )

if __name__ == '__main__':
    main()

focalizziamo le parti importanti relative a Matplotlib:

Innanzitutto importiamo Matplotlib all’interno del setup, per poter sfruttare
la funzione get_py2exe_datafiles(), che crea un lista con tutti i file
necessari da estendere alla lista data_files.

import matplotlib
...
    # images    
    path = (os.getcwd() + "\\images\\")
    data_files = [('images', [png for png in glob.glob(path + '*.png')])]
    # matplotlib
    data_files.extend(matplotlib.get_py2exe_datafiles())
...

come ultima cosa importantissima, negli “includes” espliciti da passare alle
opzioni di setup, dobbiamo aggiungere il backend utilizzato:

import matplotlib
...
    explicit_incl = ["sqlalchemy.dialects.sqlite.base",
                     "matplotlib.backends.backend_wxagg",]
...
    setup_opts = {"py2exe": {"includes": explicit_incl,
                             "compressed": 1,
                             "optimize": 2,
                             #"ascii": 1,
                             "bundle_files": 1,}}
...

link:
il mio sample,
py2exe: MatplotLib

Categorie:py2exe Tag:
I commenti sono chiusi.