From: <md...@us...> - 2007-07-31 18:42:46
|
Revision: 3646 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3646&view=rev Author: mdboom Date: 2007-07-31 11:42:39 -0700 (Tue, 31 Jul 2007) Log Message: ----------- Refactor distutils script to display information about the extensions being built. Use pkg-config to find freetype if possible. Modified Paths: -------------- trunk/matplotlib/setup.cfg trunk/matplotlib/setup.py trunk/matplotlib/setupext.py Modified: trunk/matplotlib/setup.cfg =================================================================== --- trunk/matplotlib/setup.cfg 2007-07-31 14:05:01 UTC (rev 3645) +++ trunk/matplotlib/setup.cfg 2007-07-31 18:42:39 UTC (rev 3646) @@ -1,2 +1,7 @@ [egg_info] tag_svn_revision = 1 + +[status] +# To suppress display of the dependencies and their versions +# at the top of the build log, uncomment the following line: +# suppress = 1 \ No newline at end of file Modified: trunk/matplotlib/setup.py =================================================================== --- trunk/matplotlib/setup.py 2007-07-31 14:05:01 UTC (rev 3645) +++ trunk/matplotlib/setup.py 2007-07-31 18:42:39 UTC (rev 3646) @@ -35,7 +35,7 @@ # build wxPython extension code to efficiently blit agg into wx. Only # needed for wxpython <2.8 if you plan on doing animations -BUILD_WXAGG = 0 +BUILD_WXAGG = 1 # build a small extension to manage the focus on win32 platforms. @@ -71,18 +71,57 @@ setuptools requirement, you must delete the old matplotlib install directory.""") +if major==2 and minor1<3 or major<2: + raise SystemExit("""matplotlib requires Python 2.3 or later.""") + import glob from distutils.core import setup from setupext import build_agg, build_gtkagg, build_tkagg, build_wxagg,\ build_ft2font, build_image, build_windowing, build_transforms, \ build_contour, build_nxutils, build_enthought, build_swigagg, build_gdk, \ - build_subprocess, build_ttconv + build_subprocess, build_ttconv, print_line, print_status, print_message, \ + print_raw, check_for_freetype, check_for_libpng, check_for_gtk, check_for_tk, \ + check_for_wx, check_for_numpy, check_for_qt, check_for_qt4, check_for_cairo #import distutils.sysconfig +# jdh +packages = [ + 'matplotlib', + 'matplotlib.backends', + 'matplotlib.toolkits', + 'matplotlib.numerix', + 'matplotlib.numerix.mlab', + 'matplotlib.numerix.ma', + 'matplotlib.numerix.npyma', + 'matplotlib.numerix.linear_algebra', + 'matplotlib.numerix.random_array', + 'matplotlib.numerix.fft', + 'matplotlib.config' + ] + +ext_modules = [] + +# these are not optional +BUILD_FT2FONT = 1 +BUILD_TTCONV = 1 +BUILD_CONTOUR = 1 +BUILD_NXUTILS = 1 + for line in file('lib/matplotlib/__init__.py').readlines(): - if line[:11] == '__version__': + if (line.startswith('__version__') or + line.startswith('__revision__') or + line.startswith('__date__')): exec(line.strip()) +print_line() +print_raw("BUILDING MATPLOTLIB") +print_status('matplotlib', '%s (r%s)' % (__version__, __revision__.split()[-2])) +print_status('platform', sys.platform) +if sys.platform == 'win32': + print_status('Windows version', sys.getwindowsversion()) +print_raw("") +print_raw("REQUIRED DEPENDENCIES") + # Specify all the required mpl data package_data = {'matplotlib':['mpl-data/fonts/afm/*.afm', 'mpl-data/fonts/pdfcorefonts/*.afm', @@ -98,43 +137,19 @@ 'backends/Matplotlib.nib/*', ]} +if not check_for_numpy(): + sys.exit() + # The NUMERIX variable (a list) is left over from the days when it had # a string for each of the supported backends. Now there is only one # supported backend, so this approach could (should?) get changed for # simplicity. -try: - import numpy - NUMERIX = ['numpy'] -except ImportError: - raise RuntimeError("You must install numpy to build matplotlib") +import numpy +NUMERIX = ['numpy'] rc['numerix'] = NUMERIX[-1] -ext_modules = [] - -# these are not optional -BUILD_FT2FONT = 1 -BUILD_TTCONV = 1 -BUILD_CONTOUR = 1 -BUILD_NXUTILS = 1 - -# jdh -packages = [ - 'matplotlib', - 'matplotlib.backends', - 'matplotlib.toolkits', - 'matplotlib.numerix', - 'matplotlib.numerix.mlab', - 'matplotlib.numerix.ma', - 'matplotlib.numerix.npyma', - 'matplotlib.numerix.linear_algebra', - 'matplotlib.numerix.random_array', - 'matplotlib.numerix.fft', - 'matplotlib.config' - ] - - try: import subprocess except ImportError: havesubprocess = False else: havesubprocess = True @@ -146,12 +161,28 @@ subprocess_dir = os.path.dirname(subprocess.__file__) if subprocess_dir.endswith('.egg/subprocess'): havesubprocess = False - + if not havesubprocess: packages.append('subprocess') if sys.platform == 'win32': build_subprocess(ext_modules, packages) +if not check_for_freetype(): + sys.exit(1) + +if BUILD_FT2FONT: + build_ft2font(ext_modules, packages) + +if BUILD_TTCONV: + build_ttconv(ext_modules, packages) + +if 1: # I don't think we need to make these optional + build_contour(ext_modules, packages) + build_nxutils(ext_modules, packages) + +print_raw("") +print_raw("OPTIONAL DEPENDENCIES") + try: import datetime except ImportError: havedate = False else: havedate = True @@ -174,115 +205,70 @@ add_dateutil() else: # only add them if we need them - try: import dateutil - except ImportError: - add_dateutil() - try: import pytz + try: + import pytz except ImportError: add_pytz() + try: + import dateutil + except ImportError: + add_dateutil() + build_swigagg(ext_modules, packages) build_transforms(ext_modules, packages) build_enthought(ext_modules, packages) -def havegtk(): - 'check for the presence of pygtk' - if havegtk.gotit is not None: return havegtk.gotit - try: - import gtk - except ImportError: - print 'building for GTK requires pygtk; you must be able to "import gtk" in your build/install environment' - havegtk.gotit = False - except RuntimeError: - print 'pygtk present but import failed' - havegtk.gotit = False - else: - version = (2,2,0) - if gtk.pygtk_version < version: - print "Error: GTK backend requires PyGTK %d.%d.%d (or later), " \ - "%d.%d.%d was detected." % ( - version + gtk.pygtk_version) - havegtk.gotit = False - else: - havegtk.gotit = True - return havegtk.gotit +if check_for_gtk() and (BUILD_GTK or BUILD_GTKAGG): + if BUILD_GTK: + build_gdk(ext_modules, packages) + rc['backend'] = 'GTK' + if BUILD_GTKAGG: + BUILD_AGG = 1 + build_gtkagg(ext_modules, packages) + rc['backend'] = 'GTKAgg' -havegtk.gotit = None - -if BUILD_GTK and havegtk(): - build_gdk(ext_modules, packages) - rc['backend'] = 'GTK' - -if BUILD_GTKAGG and havegtk(): +if check_for_tk() and BUILD_TKAGG: BUILD_AGG = 1 - build_gtkagg(ext_modules, packages) - rc['backend'] = 'GTKAgg' + build_tkagg(ext_modules, packages) + rc['backend'] = 'TkAgg' -if BUILD_TKAGG: - try: - import Tkinter - except ImportError: - print 'TKAgg requires TkInter' - BUILD_TKAGG = 0 - except RuntimeError: - print 'Tkinter present but import failed' - BUILD_TKAGG = 0 +explanation = None +if check_for_wx() and BUILD_WXAGG: + BUILD_AGG = 1 + import wx + if wx.__version__ < (2.8): + build_wxagg(ext_modules, packages) + wxagg_backend_status = "yes" else: - try: - tk = Tkinter.Tk() - tk.withdraw() - except Tkinter.TclError: - print 'Tkinter present, but window failed to open' - BUILD_TKAGG = 0 - else: - BUILD_AGG = 1 - build_tkagg(ext_modules, packages) - rc['backend'] = 'TkAgg' + print_message("WxAgg extension not required for wxPython < 2.8") + rc['backend'] = 'WXAgg' -if BUILD_WXAGG: - try: - import wx - except ImportError: - if BUILD_WXAGG != 'auto': - print 'WXAgg\'s accelerator requires wxPython' - BUILD_WXAGG = 0 - else: - if getattr(wx, '__version__', '0.0')[0:3] < '2.8': - BUILD_AGG = 1 - build_wxagg(ext_modules, packages, - not (isinstance(BUILD_WXAGG, str) # don't abort if BUILD_WXAGG - and BUILD_WXAGG.lower() == 'auto')) # is "auto" - rc['backend'] = 'WXAgg' - -if BUILD_AGG: +# These are informational only. We don't build +# any extensions for them. +check_for_qt() +check_for_qt4() +check_for_cairo() + +if check_for_libpng() and BUILD_AGG: build_agg(ext_modules, packages) if rc['backend'] == 'PS': rc['backend'] = 'Agg' - - -if BUILD_FT2FONT: - build_ft2font(ext_modules, packages) - -if BUILD_TTCONV: - build_ttconv(ext_modules, packages) - if BUILD_WINDOWING and sys.platform=='win32': build_windowing(ext_modules, packages) if BUILD_IMAGE: build_image(ext_modules, packages) -if 1: # I don't think we need to make these optional - build_contour(ext_modules, packages) - build_nxutils(ext_modules, packages) - for mod in ext_modules: if VERBOSE: mod.extra_compile_args.append('-DVERBOSE') +print_raw("") +print_raw("[Edit setup.cfg to suppress the above messages]") +print_line() - # packagers: set rc['numerix'] and rc['backend'] here to override the auto # defaults, eg #rc['numerix'] = numpy Modified: trunk/matplotlib/setupext.py =================================================================== --- trunk/matplotlib/setupext.py 2007-07-31 14:05:01 UTC (rev 3645) +++ trunk/matplotlib/setupext.py 2007-07-31 18:42:39 UTC (rev 3646) @@ -60,8 +60,12 @@ } import sys, os, stat +import commands +from sets import Set +from textwrap import fill from distutils.core import Extension import glob +import ConfigParser major, minor1, minor2, s, tmp = sys.version_info if major<2 or (major==2 and minor1<3): @@ -81,7 +85,7 @@ BUILT_WINDOWING = False BUILT_CONTOUR = False BUILT_NXUTILS = False -BUILT_ENTHOUGHT = False +BUILT_ENTHOUGHT = False BUILT_CONTOUR = False BUILT_GDK = False @@ -90,6 +94,42 @@ # for nonstandard installation/build with --prefix variable numpy_inc_dirs = [] +# Based on the contents of setup.cfg, determine if the status block +# should be displayed +display_status = True +if os.path.exists("setup.cfg"): + config = ConfigParser.SafeConfigParser() + config.read("setup.cfg") + try: + if config.get("status", "suppress"): + display_status = False + except: + pass + +if display_status: + def print_line(char='='): + print char * 76 + + def print_status(package, status): + initial_indent = "%22s: " % package + indent = ' ' * 24 + print fill(status, width=76, + initial_indent=initial_indent, + subsequent_indent=indent) + + def print_message(message): + indent = ' ' * 24 + "* " + print fill(message, width=76, + initial_indent=indent, + subsequent_indent=indent) + + def print_raw(section): + print section +else: + def print_line(*args, **kwargs): + pass + print_status = print_message = print_raw = print_line + class CleanUpFile: """CleanUpFile deletes the specified filename when self is destroyed.""" def __init__(self, name): @@ -123,8 +163,99 @@ else: std_libs = ['stdc++', 'm'] +def has_pkgconfig(): + if has_pkgconfig.cache is not None: + return has_pkgconfig.cache + if sys.platform == 'win32': + has_pkgconfig.cache = False + else: + status, output = commands.getstatusoutput("pkg-config --help") + has_pkgconfig.cache = (status == 0) + return has_pkgconfig.cache +has_pkgconfig.cache = None + +def get_pkgconfig(module, + packages, + flags="--libs --cflags", + pkg_config_exec='pkg-config'): + """Loosely based on an article in the Python Cookbook: + http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/502261""" + if not has_pkgconfig(): + return False + + _flags = {'-I': 'include_dirs', + '-L': 'library_dirs', + '-l': 'libraries', + '-D': 'define_macros', + '-U': 'undef_macros'} + + status, output = commands.getstatusoutput( + "%s %s %s" % (pkg_config_exec, flags, packages)) + if status == 0: + for token in output.split(): + attr = _flags.get(token[:2], None) + if attr is not None: + set = getattr(module, attr) + if token[2:] not in set: + set.append(token[2:]) + else: + if token not in module.extra_link_args: + module.extra_link_args.append(token) + return True + return False + +def get_pkgconfig_version(package): + default = "unknown (no pkg-config)" + if not has_pkgconfig(): + return default + + status, output = commands.getstatusoutput( + "pkg-config %s --modversion" % (package)) + if status == 0: + return output + return default + +def try_pkgconfig(module, package, fallback): + if not get_pkgconfig(module, package): + module.libraries.append(fallback) + +def find_include_file(include_dirs, filename): + for d in include_dirs: + if os.path.exists(os.path.join(d, filename)): + return True + return False + +def check_for_freetype(): + module = Extension('test', []) + add_base_flags(module) + if not get_pkgconfig(module, 'freetype2'): + basedirs = module.include_dirs[:] # copy the list to avoid inf loop! + for d in basedirs: + module.include_dirs.append(os.path.join(d, 'freetype2')) + + if not find_include_file(module.include_dirs, 'ft2build.h'): + print_message( + "Could not find 'freetype2' headers in any of %s" % + ", ".join(["'%s'" % x for x in module.include_dirs])) + return False + + print_status("freetype2", get_pkgconfig_version('freetype2')) + return True + +def check_for_libpng(): + module = Extension("test", []) + get_pkgconfig(module, 'libpng') + add_base_flags(module) + if not find_include_file(module.include_dirs, 'png.h'): + print_message( + ", ".join("Could not find 'libpng' headers in any of %s" % + ["'%s'" % x for x in module.include_dirs])) + return False + + print_status("libpng", get_pkgconfig_version('libpng')) + return True + def add_base_flags(module): - incdirs = filter(os.path.exists, [os.path.join(p, 'include') for p in basedir[sys.platform] ]) libdirs = filter(os.path.exists, @@ -141,6 +272,57 @@ ret = os.popen(s).read().strip() return ret +def check_for_qt(): + try: + import pyqtconfig + except ImportError: + print_status("Qt", "no") + return False + else: + print_status("Qt", "Qt: %s, pyqt: %s" % + (pyqtconfig.Configuration().pyqt_version_str, + pyqtconfig.Configuration().qt_version)) + return True + +def check_for_qt4(): + try: + import PyQt4.pyqtconfig + except ImportError: + print_status("Qt4", "no") + return False + else: + print_status("Qt4", "Qt: %s, pyqt: %s" % + (PyQt4.pyqtconfig.Configuration().pyqt_version_str, + PyQt4.pyqtconfig.Configuration().qt_version)) + return True + +def check_for_cairo(): + try: + import cairo + except ImportError: + print_status("Cairo", "no") + return False + else: + print_status("Cairo", cairo.version) + +def check_for_numpy(): + gotit = False + try: + import numpy + except ImportError: + print_status("numpy", "no") + print_message("You must install numpy to build matplotlib.") + return False + module = Extension('test', []) + add_numpy_flags(module) + add_base_flags(module) + if not find_include_file(module.include_dirs, os.path.join("numpy", "arrayobject.h")): + print_status("numpy", "no") + print_message("Could not find the headers for numpy. You may need to install the development package.") + return False + print_status("numpy", numpy.__version__) + return True + def add_numpy_flags(module): "Add the modules flags to build extensions which use numpy" import numpy @@ -154,13 +336,11 @@ 'Add the module flags to build extensions which use agg' # before adding the freetype flags since -z comes later - module.libraries.append('png') + try_pkgconfig(module, 'libpng', 'png') module.libraries.append('z') add_base_flags(module) module.include_dirs.extend(['src','swig', '%s/include'%AGG_VERSION, '.']) - - # put these later for correct link order module.libraries.extend(std_libs) @@ -168,24 +348,26 @@ 'Add the module flags to build extensions which use gd' module.libraries.append('gd') - def add_ft2font_flags(module): - 'Add the module flags to build extensions which use gd' - module.libraries.extend(['freetype', 'z' ]) + 'Add the module flags to ft2font extension' + module.libraries.append('z') add_base_flags(module) - basedirs = module.include_dirs[:] # copy the list to avoid inf loop! - for d in basedirs: - module.include_dirs.append(os.path.join(d, 'freetype2')) - p = os.path.join(d, 'lib/freetype2/include') - if os.path.exists(p): module.include_dirs.append(p) - p = os.path.join(d, 'lib/freetype2/include/freetype2') - if os.path.exists(p): module.include_dirs.append(p) + if not get_pkgconfig(module, 'freetype2'): + module.libraries.append('freetype') + + basedirs = module.include_dirs[:] # copy the list to avoid inf loop! + for d in basedirs: + module.include_dirs.append(os.path.join(d, 'freetype2')) + p = os.path.join(d, 'lib/freetype2/include') + if os.path.exists(p): module.include_dirs.append(p) + p = os.path.join(d, 'lib/freetype2/include/freetype2') + if os.path.exists(p): module.include_dirs.append(p) - basedirs = module.library_dirs[:] # copy the list to avoid inf loop! - for d in basedirs: - p = os.path.join(d, 'freetype2/lib') - if os.path.exists(p): module.library_dirs.append(p) + basedirs = module.library_dirs[:] # copy the list to avoid inf loop! + for d in basedirs: + p = os.path.join(d, 'freetype2/lib') + if os.path.exists(p): module.library_dirs.append(p) if sys.platform == 'win32' and win32_compiler == 'mingw32': module.libraries.append('gw32c') @@ -193,8 +375,48 @@ # put this last for library link order module.libraries.extend(std_libs) +def check_for_gtk(): + 'check for the presence of pygtk' + gotit = False + explanation = None + try: + import gtk + except ImportError: + explanation = 'Building for Gtk+ requires pygtk; you must be able to "import gtk" in your build/install environment' + except RuntimeError: + explanation = 'pygtk present but import failed' + else: + version = (2,2,0) + if gtk.pygtk_version < version: + explanation = "Error: GTK backend requires PyGTK %d.%d.%d (or later), " \ + "%d.%d.%d was detected." % ( + version + gtk.pygtk_version) + else: + gotit = True + if gotit: + module = Extension('test', []) + add_pygtk_flags(module) + if not find_include_file(module.include_dirs, os.path.join("gtk", "gtk.h")): + explanation = ( + "Could not find Gtk+ headers in any of %s" % + ", ".join(["'%s'" % x for x in module.include_dirs])) + gotit = False + def ver2str(tup): + return ".".join([str(x) for x in tup]) + + if gotit: + import gobject + print_status("Gtk+", "gtk+: %s, glib: %s, pygtk: %s, pygobject: %s" % + (ver2str(gtk.gtk_version), ver2str(gobject.glib_version), + ver2str(gtk.pygtk_version), ver2str(gobject.pygobject_version))) + else: + print_status("Gtk+", "no") + print_message(explanation) + + return gotit + def add_pygtk_flags(module): 'Add the module flags to build extensions which use gtk' @@ -220,36 +442,61 @@ add_base_flags(module) - # set for msvc compiler if not present - if not os.environ.has_key('PKG_CONFIG_PATH'): - os.environ['PKG_CONFIG_PATH'] = 'C:\GTK\lib\pkgconfig' + if sys.platform != 'win32': + # If Gtk+ is installed, pkg-config is required to be installed + get_pkgconfig(module, 'pygtk-2.0 gtk+-2.0') - pygtkIncludes = getoutput('pkg-config --cflags-only-I pygtk-2.0').split() - gtkIncludes = getoutput('pkg-config --cflags-only-I gtk+-2.0').split() - includes = pygtkIncludes + gtkIncludes - module.include_dirs.extend([include[2:] for include in includes]) + # visual studio doesn't need the math library + if sys.platform == 'win32' and win32_compiler == 'msvc' and 'm' in module.libraries: + module.libraries.remove('m') - pygtkLinker = getoutput('pkg-config --libs pygtk-2.0').split() - gtkLinker = getoutput('pkg-config --libs gtk+-2.0').split() - linkerFlags = pygtkLinker + gtkLinker - module.libraries.extend( - [flag[2:] for flag in linkerFlags if flag.startswith('-l')]) +def check_for_wx(): + gotit = False + explanation = None + try: + import wx + except ImportError: + explanation = 'wxPython not found' + else: + if sys.platform == 'win32' and win32_compiler == 'mingw32': + explanation = "The wxAgg extension can not be built using the mingw32 compiler on Windows, since the default wxPython binary is built using MS Visual Studio" + else: + wxconfig = find_wx_config() + if wxconfig is None: + explanation = """ +WXAgg's accelerator requires `wx-config'. +The `wx-config\' executable could not be located in any directory of the +PATH environment variable. If you want to build WXAgg, and wx-config is +in some other location or has some other name, set the WX_CONFIG +environment variable to the full path of the executable like so: - module.library_dirs.extend( - [flag[2:] for flag in linkerFlags if flag.startswith('-L')]) +export WX_CONFIG=/usr/lib/wxPython-2.6.1.0-gtk2-unicode/bin/wx-config +""" + elif not check_wxpython_broken_macosx104_version(wxconfig): + explanation = 'WXAgg\'s accelerator not building because a broken wxPython (installed by Apple\'s Mac OS X) was found.' + else: + gotit = True + if gotit: + module = Extension("test", []) + add_wx_flags(module, wxconfig) + if not find_include_file( + module.include_dirs, + os.path.join("wx", "wxPython", "wxPython.h")): + explanation = ("Could not find wxPython headers in any of %s" % + ", ".join(["'%s'" % x for x in module.include_dirs])) + gotit = False - module.extra_link_args.extend( - [flag for flag in linkerFlags if not - (flag.startswith('-l') or flag.startswith('-L'))]) - - # visual studio doesn't need the math library - if sys.platform == 'win32' and win32_compiler == 'msvc' and 'm' in module.libraries: - module.libraries.remove('m') - - + if gotit: + print_status("wxPython", wx.__version__) + else: + print_status("wxPython", "no") + if explanation is not None: + print_message(explanation) + return gotit + def find_wx_config(): """If the WX_CONFIG environment variable has been set, returns it value. Otherwise, search for `wx-config' in the PATH directories and return the @@ -268,24 +515,6 @@ return None - -def check_wxpython_headers(wxconfig): - """Determines if wxPython.h can be found in one of the wxWidgets include - directories. - """ - - flags = getoutput(wxconfig + ' --cppflags').split() - incdirs = [os.path.join(p, 'include') for p in basedir[sys.platform] - if os.path.exists(p)] - - incdirs += [x[2:] for x in flags if x.startswith('-I')] - header = os.path.join('wx', 'wxPython', 'wxPython.h') - - for d in incdirs: - if os.path.exists(os.path.join(d, header)): - return True - return False - def check_wxpython_broken_macosx104_version(wxconfig): """Determines if we're using a broken wxPython installed by Mac OS X 10.4""" if sys.platform == 'darwin': @@ -308,31 +537,8 @@ module.libraries.extend(wxlibs) return - def getWX(fmt, *args): - return getoutput(wxconfig + ' ' + (fmt % args)).split() + get_pkgconfig(module, '', flags='--cppflags --libs', pkg_config_exec='wx-config') - wxFlags = getWX('--cppflags') - wxLibs = getWX('--libs') - - - add_base_flags(module) - module.include_dirs.extend( - [x[2:] for x in wxFlags if x.startswith('-I')]) - - - module.define_macros.extend( - [(x[2:], None) for x in wxFlags if x.startswith('-D')]) - module.undef_macros.extend( - [x[2:] for x in wxFlags if x.startswith('-U')]) - - module.libraries.extend( - [x[2:] for x in wxLibs if x.startswith('-l')]) - module.library_dirs.extend( - [x[2:] for x in wxLibs if x.startswith('-L')]) - module.extra_link_args.extend( - [x for x in wxLibs if not (x.startswith('-l') or x.startswith('-L'))]) - - # Make sure you use the Tk version given by Tkinter.TkVersion # or else you'll build for a wrong version of the Tcl # interpreter (leading to nasty segfaults). @@ -342,21 +548,12 @@ def find_tcltk(): """Finds Tcl/Tk includes/libraries/version by interrogating Tkinter.""" - try: - import Tkinter - except: - print "Tkinter not properly installed\n" - sys.exit(1) - if Tkinter.TkVersion < 8.3: - print "Tcl/Tk v8.3 or later required\n" - sys.exit(1) + # By this point, we already know that Tkinter imports correctly + import Tkinter o = FoundTclTk() try: tk=Tkinter.Tk() except Tkinter.TclError: - print "Using default library and include directories for Tcl and Tk because a" - print "Tk window failed to open. You may need to define DISPLAY for Tk to work" - print "so that setup can determine where your libraries are located." o.tcl_lib = "/usr/local/lib" o.tcl_inc = "/usr/local/include" o.tk_lib = "/usr/local/lib" @@ -389,24 +586,60 @@ os.path.exists('/usr/include/tk.h')): o.tcl_inc = '/usr/include/' o.tk_inc = '/usr/include/' - - if not os.path.exists(o.tcl_inc): - print 'cannot find tcl/tk headers. giving up.' - sys.exit() return o +def check_for_tk(): + gotit = False + explanation = None + try: + import Tkinter + except ImportError: + explanation = 'TKAgg requires Tkinter' + except RuntimeError: + explanation = 'Tkinter present but import failed' + else: + if Tkinter.TkVersion < 8.3: + explanation = "Tcl/Tk v8.3 or later required\n" + sys.exit(1) + else: + try: + tk = Tkinter.Tk() + tk.withdraw() + except Tkinter.TclError: + explanation = """\ +Using default library and include directories for Tcl and Tk because a +Tk window failed to open. You may need to define DISPLAY for Tk to work +so that setup can determine where your libraries are located.""" + gotit = True + if gotit: + module = Extension('test', []) + try: + add_tk_flags(module) + except RuntimeError, e: + explanation = str(e) + gotit = False + if not find_include_file(module.include_dirs, "tk.h"): + explanation = 'Tkinter present, but header files are not installed. You may need to install development packages.' + gotit = False + + if gotit: + print_status("Tkinter", "Tkinter: %s, Tk: %s, Tcl: %s" % + (Tkinter.__version__.split()[-2], Tkinter.TkVersion, Tkinter.TclVersion)) + else: + print_status("Tkinter", "no") + if explanation is not None: + print_message(explanation) + return gotit + def add_tk_flags(module): 'Add the module flags to build extensions which use tk' if sys.platform=='win32': major, minor1, minor2, s, tmp = sys.version_info - print 'building tkagg', major, minor1 if major==2 and minor1 in [3, 4, 5]: - print '\tBuilding for python2%d'%minor1 module.include_dirs.extend(['win32_static/include/tcl84']) module.libraries.extend(['tk84', 'tcl84']) elif major==2 and minor1==2: - print '\tBuilding for python22' module.include_dirs.extend(['win32_static/include/tcl83']) module.libraries.extend(['tk83', 'tcl83']) else: @@ -503,7 +736,10 @@ def build_ttconv(ext_modules, packages): global BUILT_TTCONV if BUILT_TTCONV: return # only build it if you you haven't already - deps = ['src/_ttconv.cpp', 'ttconv/pprdrv_tt.cpp', 'ttconv/pprdrv_tt2.cpp', 'ttconv/ttutil.cpp'] + deps = ['src/_ttconv.cpp', + 'ttconv/pprdrv_tt.cpp', + 'ttconv/pprdrv_tt2.cpp', + 'ttconv/ttutil.cpp'] deps.extend(glob.glob('CXX/*.cxx')) deps.extend(glob.glob('CXX/*.c')) @@ -523,11 +759,9 @@ deps, ) - # add agg flags before pygtk because agg only supports freetype1 # and pygtk includes freetype2. This is a bit fragile. - add_agg_flags(module) add_ft2font_flags(module) add_pygtk_flags(module) @@ -557,62 +791,11 @@ BUILT_TKAGG = True -def build_wxagg(ext_modules, packages, abortOnFailure): +def build_wxagg(ext_modules, packages): global BUILT_WXAGG if BUILT_WXAGG: return - wxconfig = find_wx_config() - - # Avoid aborting the whole build process if `wx-config' can't be found and - # BUILD_WXAGG in setup.py is set to "auto" - if sys.platform == 'win32': - # mingw32 cannot link against distributed wx libs - # since they are built with VisualStudio - if win32_compiler == 'mingw32': - return - else: - pass - - elif wxconfig is None: - print """ -WXAgg's accelerator requires `wx-config'. - -The `wx-config\' executable could not be located in any directory of the -PATH environment variable. If you want to build WXAgg, and wx-config is -in some other location or has some other name, set the WX_CONFIG -environment variable to the full path of the executable like so: - -export WX_CONFIG=/usr/lib/wxPython-2.6.1.0-gtk2-unicode/bin/wx-config -""" - if not abortOnFailure: - print """Building MPL without wxAgg""" - BUILT_WXAGG = True - return - else: - sys.exit(1) - elif not check_wxpython_headers(wxconfig): - print 'WXAgg\'s accelerator requires the wxPython headers.' - - if not abortOnFailure: - BUILT_WXAGG = True - return - else: - print """ -The wxPython header files could not be located in any of the standard -include -directories or include directories reported by `wx-config --cppflags'.""" - sys.exit(1) - elif not check_wxpython_broken_macosx104_version(wxconfig): - print 'WXAgg\'s accelerator not building because a broken wxPython (installed by Apple\'s Mac OS X) was found.' - if not abortOnFailure: - BUILT_WXAGG = True - return - else: - print """ -The wxPython installation is the broken version installed with Mac OS X 10.4.""" - sys.exit(1) - deps = ['src/_wxagg.cpp', 'src/mplutils.cpp'] deps.extend(glob.glob('CXX/*.cxx')) deps.extend(glob.glob('CXX/*.c')) @@ -627,8 +810,6 @@ BUILT_WXAGG = True - - def build_agg(ext_modules, packages): global BUILT_AGG if BUILT_AGG: return # only build it if you you haven't already This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-01 12:26:56
|
Revision: 3649 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3649&view=rev Author: mdboom Date: 2007-08-01 05:26:55 -0700 (Wed, 01 Aug 2007) Log Message: ----------- Fix wx check and build Modified Paths: -------------- trunk/matplotlib/setup.py trunk/matplotlib/setupext.py Modified: trunk/matplotlib/setup.py =================================================================== --- trunk/matplotlib/setup.py 2007-08-01 12:19:03 UTC (rev 3648) +++ trunk/matplotlib/setup.py 2007-08-01 12:26:55 UTC (rev 3649) @@ -238,7 +238,7 @@ if check_for_wx() and BUILD_WXAGG: BUILD_AGG = 1 import wx - if wx.__version__ < (2.8): + if getattr(wx, '__version__', '0.0')[0:3] < '2.8': build_wxagg(ext_modules, packages) wxagg_backend_status = "yes" else: Modified: trunk/matplotlib/setupext.py =================================================================== --- trunk/matplotlib/setupext.py 2007-08-01 12:19:03 UTC (rev 3648) +++ trunk/matplotlib/setupext.py 2007-08-01 12:26:55 UTC (rev 3649) @@ -485,14 +485,15 @@ gotit = True if gotit: - module = Extension("test", []) - add_wx_flags(module, wxconfig) - if not find_include_file( - module.include_dirs, - os.path.join("wx", "wxPython", "wxPython.h")): - explanation = ("Could not find wxPython headers in any of %s" % - ", ".join(["'%s'" % x for x in module.include_dirs])) - gotit = False + if getattr(wx, '__version__', '0.0')[0:3] < '2.8': + module = Extension("test", []) + add_wx_flags(module, wxconfig) + if not find_include_file( + module.include_dirs, + os.path.join("wx", "wxPython", "wxPython.h")): + explanation = ("Could not find wxPython headers in any of %s" % + ", ".join(["'%s'" % x for x in module.include_dirs])) + gotit = False if gotit: print_status("wxPython", wx.__version__) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-02 18:37:33
|
Revision: 3664 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3664&view=rev Author: mdboom Date: 2007-08-02 11:37:32 -0700 (Thu, 02 Aug 2007) Log Message: ----------- Add kwarg 'markup' for all text that allows the user to choose either 'plain' or 'tex' markup. A default may also be provided in the rcParam 'text.markup'. Minor bugfix to mathtext.py Modified Paths: -------------- trunk/matplotlib/examples/accented_text.py trunk/matplotlib/examples/arrow_demo.py trunk/matplotlib/examples/dannys_example.py trunk/matplotlib/examples/histogram_demo.py trunk/matplotlib/examples/histogram_demo_canvasagg.py trunk/matplotlib/examples/integral_demo.py trunk/matplotlib/examples/legend_auto.py trunk/matplotlib/examples/mathtext_demo.py trunk/matplotlib/examples/mathtext_examples.py trunk/matplotlib/examples/scatter_demo2.py trunk/matplotlib/examples/tex_demo.py trunk/matplotlib/examples/tex_unicode_demo.py trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/lib/matplotlib/rcsetup.py trunk/matplotlib/lib/matplotlib/text.py trunk/matplotlib/matplotlibrc.template Modified: trunk/matplotlib/examples/accented_text.py =================================================================== --- trunk/matplotlib/examples/accented_text.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/accented_text.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -13,9 +13,9 @@ plot(range(10)) -title(r'$\ddot{o}\acute{e}\grave{e}\hat{O}\breve{i}\bar{A}\tilde{n}\vec{q}$', fontsize=20) +title(r'$\ddot{o}\acute{e}\grave{e}\hat{O}\breve{i}\bar{A}\tilde{n}\vec{q}$', fontsize=20, markup="tex") # shorthand is also supported and curly's are optional -xlabel(r"""$\"o\ddot o \'e\`e\~n\.x\^y$""", fontsize=20) +xlabel(r"""$\"o\ddot o \'e\`e\~n\.x\^y$""", fontsize=20, markup="tex") show() Modified: trunk/matplotlib/examples/arrow_demo.py =================================================================== --- trunk/matplotlib/examples/arrow_demo.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/arrow_demo.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -52,7 +52,7 @@ min_text_size = size label_text_size = size*2.5 text_params={'ha':'center', 'va':'center', 'family':'sans-serif',\ - 'fontweight':'bold'} + 'fontweight':'bold', 'markup': 'tex'} r2 = sqrt(2) deltas = {\ @@ -211,7 +211,7 @@ label = '$%s_{_{\mathrm{%s}}}$' % (orig_label[0], orig_label[1:]) text(x, y, label, size=label_text_size, ha='center', va='center', \ - color=labelcolor or fc) + color=labelcolor or fc, markup='tex') for p in positions.keys(): draw_arrow(p) Modified: trunk/matplotlib/examples/dannys_example.py =================================================================== --- trunk/matplotlib/examples/dannys_example.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/dannys_example.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -29,14 +29,14 @@ pylab.plot((-delta / 2, -delta / 2 + offset * 2), (height, height + offset), 'k', linewidth = 2) pylab.plot((delta / 2, delta / 2 - offset * 2), (height, height - offset), 'k', linewidth = 2) pylab.plot((delta / 2, delta / 2 - offset * 2), (height, height + offset), 'k', linewidth = 2) -pylab.text(-0.06, height - 0.06, r'$\delta$', {'color' : 'k', 'fontsize' : 24}) +pylab.text(-0.06, height - 0.06, r'$\delta$', {'color' : 'k', 'fontsize' : 24}, markup = 'tex') ## X-axis label pylab.xticks((-1, 0, 1), ('-1', '0', '1'), color = 'k', size = 20) ## Left Y-axis labels pylab.ylabel(r'\bf{phase field} $\phi$', {'color' : 'b', - 'fontsize' : 20 }) + 'fontsize' : 20 }, markup='tex') pylab.yticks((0, 0.5, 1), ('0', '.5', '1'), color = 'k', size = 20) ## Right Y-axis labels @@ -44,16 +44,17 @@ horizontalalignment = 'left', verticalalignment = 'center', rotation = 90, - clip_on = False) + clip_on = False, + markup = 'tex') pylab.text(1.01, -0.02, "-1", {'color' : 'k', 'fontsize' : 20}) pylab.text(1.01, 0.98, "1", {'color' : 'k', 'fontsize' : 20}) pylab.text(1.01, 0.48, "0", {'color' : 'k', 'fontsize' : 20}) ## level set equations -pylab.text(0.1, 0.85, r'$|\nabla\phi| = 1,$ \newline $ \frac{\partial \phi}{\partial t} + U|\nabla \phi| = 0$', {'color' : 'g', 'fontsize' : 20}) +pylab.text(0.1, 0.85, r'$|\nabla\phi| = 1,$ \newline $ \frac{\partial \phi}{\partial t} + U|\nabla \phi| = 0$', {'color' : 'g', 'fontsize' : 20}, markup='tex') ## phase field equations -pylab.text(0.2, 0.15, r'$\mathcal{F} = \int f\left( \phi, c \right) dV,$ \newline $ \frac{ \partial \phi } { \partial t } = -M_{ \phi } \frac{ \delta \mathcal{F} } { \delta \phi }$', {'color' : 'b', 'fontsize' : 20}) +pylab.text(0.2, 0.15, r'$\mathcal{F} = \int f\left( \phi, c \right) dV,$ \newline $ \frac{ \partial \phi } { \partial t } = -M_{ \phi } \frac{ \delta \mathcal{F} } { \delta \phi }$', {'color' : 'b', 'fontsize' : 20}, markup='tex') pylab.savefig('pfm-lsm.png') pylab.show() Modified: trunk/matplotlib/examples/histogram_demo.py =================================================================== --- trunk/matplotlib/examples/histogram_demo.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/histogram_demo.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -15,7 +15,7 @@ xlabel('Smarts') ylabel('Probability') -title(r'$\rm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$') +title(r'$\mathrm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$', markup='tex') axis([40, 160, 0, 0.03]) grid(True) Modified: trunk/matplotlib/examples/histogram_demo_canvasagg.py =================================================================== --- trunk/matplotlib/examples/histogram_demo_canvasagg.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/histogram_demo_canvasagg.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -33,7 +33,7 @@ ax.set_xlabel('Smarts') ax.set_ylabel('Probability') -ax.set_title(r'$\rm{Histogram of IQ: }\mu=100, \sigma=15$') +ax.set_title(r'$\mathrm{Histogram of IQ: }\mu=100, \sigma=15$', markup='tex') ax.set_xlim( (40, 160)) ax.set_ylim( (0, 0.03)) Modified: trunk/matplotlib/examples/integral_demo.py =================================================================== --- trunk/matplotlib/examples/integral_demo.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/integral_demo.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -22,8 +22,8 @@ ax.add_patch(poly) text(0.5 * (a + b), 30, - r"$\int_a^b f(x)\rm{d}x$", horizontalalignment='center', - fontsize=20) + r"$\int_a^b f(x)\mathrm{d}x$", horizontalalignment='center', + fontsize=20, markup='tex') axis([0,10, 0, 180]) figtext(0.9, 0.05, 'x') Modified: trunk/matplotlib/examples/legend_auto.py =================================================================== --- trunk/matplotlib/examples/legend_auto.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/legend_auto.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -51,9 +51,9 @@ def fig_7(): figure(7) xx = x - (N/2.0) - plot(xx, (xx*xx)-1225, 'bo', label='$y=x^2$') - plot(xx, 25*xx, 'go', label='$y=25x$') - plot(xx, -25*xx, 'mo', label='$y=-25x$') + plot(xx, (xx*xx)-1225, 'bo', label='$y=x^2$', markup='tex') + plot(xx, 25*xx, 'go', label='$y=25x$', markup='tex') + plot(xx, -25*xx, 'mo', label='$y=-25x$', markup='tex') legend() def fig_8(): Modified: trunk/matplotlib/examples/mathtext_demo.py =================================================================== --- trunk/matplotlib/examples/mathtext_demo.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/mathtext_demo.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -17,7 +17,7 @@ ax.set_ylabel(r'$\Delta_{i+1}^j$', fontsize=20) tex = r'$\mathcal{R}\prod_{i=\alpha_{i+1}}^\infty a_i\sin(2 \pi f x_i)$' -ax.text(1, 1.6, tex, fontsize=20, va='bottom') +ax.text(1, 1.6, tex, fontsize=20, va='bottom', markup="tex") #title(r'$\Delta_i^j \hspace{0.4} \rm{versus} \hspace{0.4} \Delta_{i+1}^j$', fontsize=20) fig.savefig('mathtext_demo') Modified: trunk/matplotlib/examples/mathtext_examples.py =================================================================== --- trunk/matplotlib/examples/mathtext_examples.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/mathtext_examples.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -62,7 +62,7 @@ x = arange(0.0, 3.0, 0.1) grid(True) - text(1, 1.6, s, fontsize=20) + text(1, 1.6, s, fontsize=20, markup="tex") savefig('mathtext_example%02d' % i) figure() Modified: trunk/matplotlib/examples/scatter_demo2.py =================================================================== --- trunk/matplotlib/examples/scatter_demo2.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/scatter_demo2.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -11,8 +11,8 @@ close = 0.003*intc.close[:-2]/0.003*intc.open[:-2] p = scatter(delta1[:-1], delta1[1:], c=close, s=volume, alpha=0.75) -xlabel(r'$\Delta_i$', size='x-large') -ylabel(r'$\Delta_{i+1}$', size='x-large') +xlabel(r'$\Delta_i$', size='x-large', markup='tex') +ylabel(r'$\Delta_{i+1}$', size='x-large', markup='tex') title(r'Volume and percent change') grid(True) #savefig('scatter_demo2') Modified: trunk/matplotlib/examples/tex_demo.py =================================================================== --- trunk/matplotlib/examples/tex_demo.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/tex_demo.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -23,10 +23,10 @@ s = cos(2*2*pi*t)+2 plot(t, s) -xlabel(r'\textbf{time (s)}') -ylabel(r'\textit{voltage (mV)}',fontsize=16) +xlabel(r'\textbf{time (s)}', markup='tex') +ylabel(r'\textit{voltage (mV)}',fontsize=16, markup='tex') title(r"\TeX\ is Number $\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!", - fontsize=16, color='r') + fontsize=16, color='r', markup='tex') grid(True) savefig('tex_demo') Modified: trunk/matplotlib/examples/tex_unicode_demo.py =================================================================== --- trunk/matplotlib/examples/tex_unicode_demo.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/examples/tex_unicode_demo.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -17,11 +17,11 @@ s = cos(2*2*pi*t)+2 plot(t, s) -xlabel(r'\textbf{time (s)}') +xlabel(r'\textbf{time (s)}', markup='tex') s = unicode(r'\textit{Velocity (\xB0/sec)}','latin-1') -ylabel(unicode(r'\textit{Velocity (\xB0/sec)}','latin-1'),fontsize=16) +ylabel(unicode(r'\textit{Velocity (\xB0/sec)}','latin-1'),fontsize=16, markup='tex') title(r"\TeX\ is Number $\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!", - fontsize=16, color='r') + fontsize=16, color='r', markup='tex') grid(True) savefig('tex_demo') Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -1840,6 +1840,8 @@ ) ) + self.clear() + def clear(self): self._expr = None self._state_stack = None Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py =================================================================== --- trunk/matplotlib/lib/matplotlib/rcsetup.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -198,6 +198,11 @@ except ValueError: raise ValueError('not a valid font size') +validate_markup = ValidateInStrings( + 'markup', + ['plain', 'tex'], + ignorecase=True) + validate_verbose = ValidateInStrings('verbose',[ 'silent', 'helpful', 'debug', 'debug-annoying', ]) @@ -350,8 +355,8 @@ 'text.fontvariant' : ['normal', str], 'text.fontweight' : ['normal', str], 'text.fontsize' : ['medium', validate_fontsize], + 'text.markup' : ['plain', validate_markup], - 'image.aspect' : ['equal', validate_aspect], # equal, auto, a number 'image.interpolation' : ['bilinear', str], 'image.cmap' : ['jet', str], # one of gray, jet, etc Modified: trunk/matplotlib/lib/matplotlib/text.py =================================================================== --- trunk/matplotlib/lib/matplotlib/text.py 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/lib/matplotlib/text.py 2007-08-02 18:37:32 UTC (rev 3664) @@ -146,6 +146,7 @@ fontproperties=None, # defaults to FontProperties() rotation=None, linespacing=None, + markup=None, **kwargs ): """ @@ -174,6 +175,7 @@ if linespacing is None: linespacing = 1.2 # Maybe use rcParam later. self._linespacing = linespacing + self.set_markup(markup) self.update(kwargs) #self.set_bbox(dict(pad=0)) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd @@ -222,6 +224,7 @@ self._rotation = other._rotation self._picker = other._picker self._linespacing = other._linespacing + self._markup = other._markup def _get_layout(self, renderer): @@ -752,11 +755,11 @@ self._substrings = [] # ignore embedded mathtext for now def is_math_text(self): - if rcParams['text.usetex']: return 'TeX' - if not matplotlib._havemath: return False - if len(self._text)<2: return False - dollar_signs = self._text.count('$') - self._text.count('\\$') - return dollar_signs > 0 and dollar_signs % 2 == 0 + if rcParams['text.usetex']: return 'TeX' + if self._markup.lower() == 'tex': + if not matplotlib._havemath: return False + return True + return False def set_fontproperties(self, fp): """ @@ -766,9 +769,20 @@ """ self._fontproperties = fp + def set_markup(self, markup): + """ + Set the type of markup used for this text. + ACCEPTS: 'plain' for plain text, 'tex' for TeX-like markup + None to use the default text.markup value. + """ + if markup is None: + self._markup = rcParams['text.markup'] + elif markup.lower() in ('plain', 'tex'): + self._markup = markup.lower() + else: + raise ValueError("Markup type must be 'plain' or 'tex'") - def _get_layout_super(self, renderer, m): """ a special case optimization if a log super and angle = 0 Modified: trunk/matplotlib/matplotlibrc.template =================================================================== --- trunk/matplotlib/matplotlibrc.template 2007-08-02 15:15:29 UTC (rev 3663) +++ trunk/matplotlib/matplotlibrc.template 2007-08-02 18:37:32 UTC (rev 3664) @@ -150,6 +150,14 @@ #text.dvipnghack : False # some versions of dvipng don't handle # alpha channel properly. Use True to correct and flush # ~/.matplotlib/tex.cache before testing +#text.markup : 'plain' # Affects how text, such as titles and lables, are + # interpreted by default. + # 'plain': As plain, unformatted text + # 'tex': As TeX-like text. Text between $'s will be + # formatted as a TeX math expression. + # This setting has no effect when text.usetex is True. + # In that case, all text will be sent to TeX for + # processing. ### AXES # default face and edge color, default tick sizes, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-02 18:59:31
|
Revision: 3666 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3666&view=rev Author: mdboom Date: 2007-08-02 11:59:29 -0700 (Thu, 02 Aug 2007) Log Message: ----------- Add support for \widehat and \widetilde Modified Paths: -------------- trunk/matplotlib/examples/mathtext_examples.py trunk/matplotlib/lib/matplotlib/_mathtext_data.py trunk/matplotlib/lib/matplotlib/mathtext.py Modified: trunk/matplotlib/examples/mathtext_examples.py =================================================================== --- trunk/matplotlib/examples/mathtext_examples.py 2007-08-02 18:49:17 UTC (rev 3665) +++ trunk/matplotlib/examples/mathtext_examples.py 2007-08-02 18:59:29 UTC (rev 3666) @@ -36,7 +36,8 @@ r'$\frac{x_2888}{y}$', r"$\sqrt[3]{\frac{X_2}{Y}}=5$", r"$\sqrt[3]{x}=5$", - r'$\frac{X}{\frac{X}{Y}}$' + r'$\frac{X}{\frac{X}{Y}}$', + r'$\widehat{abc}\widetilde{def}$' ] from pylab import * Modified: trunk/matplotlib/lib/matplotlib/_mathtext_data.py =================================================================== --- trunk/matplotlib/lib/matplotlib/_mathtext_data.py 2007-08-02 18:49:17 UTC (rev 3665) +++ trunk/matplotlib/lib/matplotlib/_mathtext_data.py 2007-08-02 18:59:29 UTC (rev 3666) @@ -39,6 +39,8 @@ r'\}' : ('cmex10', 130), r'\leftangle' : ('cmex10', 97), r'\rightangle' : ('cmex10', 64), + r'\widehat' : ('cmex10', 15), + r'\widetilde' : ('cmex10', 52), r'\omega' : ('cmmi10', 29), r'\varepsilon' : ('cmmi10', 20), Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-02 18:49:17 UTC (rev 3665) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-02 18:59:29 UTC (rev 3666) @@ -1437,7 +1437,7 @@ of some characters (such as the BaKoMa fonts), the correct glyph will be selected, otherwise this will always just return a scaled version of the glyph.""" - def __init__(self, c, width, state, always=False): + def __init__(self, c, width, state, always=False, char_class=Char): alternatives = state.font_output.get_sized_alternatives_for_symbol( state.font, c) @@ -1445,7 +1445,7 @@ big_enough = False for fontname, sym in alternatives: state.font = fontname - char = Char(sym, state) + char = char_class(sym, state) if char.width > width: big_enough = True break @@ -1455,7 +1455,7 @@ if not big_enough: factor = width / char.width state.fontsize *= factor - char = Char(sym, state) + char = char_class(sym, state) Hlist.__init__(self, [char]) @@ -1969,12 +1969,15 @@ raise ParseFatalException("Error parsing accent") accent, sym = toks[0] if accent in self._wide_accents: - accent = AutoWidthChar(accent, sym.width, state) + accent = AutoWidthChar( + accent, sym.width, state, char_class=Accent) + shift_amount = 0. else: accent = Accent(self._accent_map[accent], state) + shift_amount = accent._metrics.xmin centered = HCentered([accent]) centered.hpack(sym.width, 'exactly') - centered.shift_amount = accent._metrics.xmin + centered.shift_amount = shift_amount return Vlist([ centered, Vbox(0., thickness * 2.0), This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-02 21:32:33
|
Revision: 3668 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3668&view=rev Author: mdboom Date: 2007-08-02 14:32:30 -0700 (Thu, 02 Aug 2007) Log Message: ----------- Attempting to reduce compiler warnings for gcc-4.2 (which I don't have, but Darren Dale has reported some new warnings). Modified Paths: -------------- trunk/matplotlib/src/_ttconv.cpp trunk/matplotlib/src/ft2font.cpp trunk/matplotlib/ttconv/pprdrv_tt.cpp trunk/matplotlib/ttconv/truetype.h Modified: trunk/matplotlib/src/_ttconv.cpp =================================================================== --- trunk/matplotlib/src/_ttconv.cpp 2007-08-02 19:07:02 UTC (rev 3667) +++ trunk/matplotlib/src/_ttconv.cpp 2007-08-02 21:32:30 UTC (rev 3668) @@ -83,10 +83,10 @@ int fonttype; std::vector<int> glyph_ids; - static char *kwlist[] = { "filename", "output", "fonttype", "glyph_ids", NULL }; + static const char *kwlist[] = { "filename", "output", "fonttype", "glyph_ids", NULL }; if (! PyArg_ParseTupleAndKeywords (args, kwds, - "sO&i|O&:convert_ttf_to_ps", kwlist, + "sO&i|O&:convert_ttf_to_ps", (char **)kwlist, &filename, fileobject_to_PythonFileWriter, &output, @@ -140,10 +140,10 @@ std::vector<int> glyph_ids; PyObject* result; - static char *kwlist[] = { "filename", "glyph_ids", NULL }; + static const char *kwlist[] = { "filename", "glyph_ids", NULL }; if (! PyArg_ParseTupleAndKeywords (args, kwds, - "s|O&:convert_ttf_to_ps", kwlist, + "s|O&:convert_ttf_to_ps", (char **)kwlist, &filename, pyiterable_to_vector_int, &glyph_ids)) Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007-08-02 19:07:02 UTC (rev 3667) +++ trunk/matplotlib/src/ft2font.cpp 2007-08-02 21:32:30 UTC (rev 3668) @@ -1370,8 +1370,8 @@ std::string tagname = Py::String(args[0]); int tag; - char *tags[] = {"head", "maxp", "OS/2", "hhea", - "vhea", "post", "pclt", NULL}; + static const char *tags[] = {"head", "maxp", "OS/2", "hhea", + "vhea", "post", "pclt", NULL}; for (tag=0; tags[tag] != NULL; tag++) if (strcmp(tagname.c_str(), tags[tag]) == 0) Modified: trunk/matplotlib/ttconv/pprdrv_tt.cpp =================================================================== --- trunk/matplotlib/ttconv/pprdrv_tt.cpp 2007-08-02 19:07:02 UTC (rev 3667) +++ trunk/matplotlib/ttconv/pprdrv_tt.cpp 2007-08-02 21:32:30 UTC (rev 3668) @@ -107,7 +107,7 @@ ** is always 4 characters, though the last characters may be ** padding spaces. -----------------------------------------------------------------------*/ -BYTE *GetTable(struct TTFONT *font, char *name) +BYTE *GetTable(struct TTFONT *font, const char *name) { BYTE *ptr; ULONG x; @@ -654,7 +654,7 @@ */ void ttfont_sfnts(TTStreamWriter& stream, struct TTFONT *font) { - char *table_names[]= /* The names of all tables */ + const char *table_names[]= /* The names of all tables */ { /* which it is worth while */ "cvt ", /* to include in a Type 42 */ "fpgm", /* PostScript font. */ @@ -828,7 +828,7 @@ ** this array will instead convert PostScript character names ** to executable proceedures. --------------------------------------------------------------*/ -char *Apple_CharStrings[]={ +const char *Apple_CharStrings[]={ ".notdef",".null","nonmarkingreturn","space","exclam","quotedbl","numbersign", "dollar","percent","ampersand","quotesingle","parenleft","parenright", "asterisk","plus", "comma","hyphen","period","slash","zero","one","two", @@ -871,7 +871,7 @@ ** This routine is called by the one below. ** It is also called from pprdrv_tt2.c */ -char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex) +const char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex) { int GlyphIndex; static char temp[80]; @@ -1227,7 +1227,7 @@ i != glyph_ids.end(); ++i) { StringStreamWriter writer; tt_type3_charproc(writer, &font, *i); - char* name = ttfont_CharStrings_getname(&font, *i); + const char* name = ttfont_CharStrings_getname(&font, *i); dict.add_pair(name, writer.str().c_str()); } } Modified: trunk/matplotlib/ttconv/truetype.h =================================================================== --- trunk/matplotlib/ttconv/truetype.h 2007-08-02 19:07:02 UTC (rev 3667) +++ trunk/matplotlib/ttconv/truetype.h 2007-08-02 21:32:30 UTC (rev 3668) @@ -51,13 +51,13 @@ font_type_enum target_type; /* 42 or 3 for PS, or -3 for PDF */ ULONG numTables; /* number of tables present */ - char *PostName; /* Font's PostScript name */ - char *FullName; /* Font's full name */ - char *FamilyName; /* Font's family name */ - char *Style; /* Font's style string */ - char *Copyright; /* Font's copyright string */ - char *Version; /* Font's version string */ - char *Trademark; /* Font's trademark string */ + const char *PostName; /* Font's PostScript name */ + const char *FullName; /* Font's full name */ + const char *FamilyName; /* Font's family name */ + const char *Style; /* Font's style string */ + const char *Copyright; /* Font's copyright string */ + const char *Version; /* Font's version string */ + const char *Trademark; /* Font's trademark string */ int llx,lly,urx,ury; /* bounding box */ Fixed TTVersion; /* Truetype version number from offset table */ @@ -98,7 +98,7 @@ /* This is the one routine in pprdrv_tt.c that is */ /* called from pprdrv_tt.c. */ -char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex); +const char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex); void tt_type3_charproc(TTStreamWriter& stream, struct TTFONT *font, int charindex); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-02 22:49:03
|
Revision: 3669 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3669&view=rev Author: mdboom Date: 2007-08-02 15:49:01 -0700 (Thu, 02 Aug 2007) Log Message: ----------- Reverting last change since it breaks on gcc-4.2 Modified Paths: -------------- trunk/matplotlib/src/_ttconv.cpp trunk/matplotlib/src/ft2font.cpp trunk/matplotlib/ttconv/pprdrv_tt.cpp trunk/matplotlib/ttconv/truetype.h Modified: trunk/matplotlib/src/_ttconv.cpp =================================================================== --- trunk/matplotlib/src/_ttconv.cpp 2007-08-02 21:32:30 UTC (rev 3668) +++ trunk/matplotlib/src/_ttconv.cpp 2007-08-02 22:49:01 UTC (rev 3669) @@ -83,10 +83,10 @@ int fonttype; std::vector<int> glyph_ids; - static const char *kwlist[] = { "filename", "output", "fonttype", "glyph_ids", NULL }; + static char *kwlist[] = { "filename", "output", "fonttype", "glyph_ids", NULL }; if (! PyArg_ParseTupleAndKeywords (args, kwds, - "sO&i|O&:convert_ttf_to_ps", (char **)kwlist, + "sO&i|O&:convert_ttf_to_ps", kwlist, &filename, fileobject_to_PythonFileWriter, &output, @@ -140,10 +140,10 @@ std::vector<int> glyph_ids; PyObject* result; - static const char *kwlist[] = { "filename", "glyph_ids", NULL }; + static char *kwlist[] = { "filename", "glyph_ids", NULL }; if (! PyArg_ParseTupleAndKeywords (args, kwds, - "s|O&:convert_ttf_to_ps", (char **)kwlist, + "s|O&:convert_ttf_to_ps", kwlist, &filename, pyiterable_to_vector_int, &glyph_ids)) Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007-08-02 21:32:30 UTC (rev 3668) +++ trunk/matplotlib/src/ft2font.cpp 2007-08-02 22:49:01 UTC (rev 3669) @@ -1370,8 +1370,8 @@ std::string tagname = Py::String(args[0]); int tag; - static const char *tags[] = {"head", "maxp", "OS/2", "hhea", - "vhea", "post", "pclt", NULL}; + char *tags[] = {"head", "maxp", "OS/2", "hhea", + "vhea", "post", "pclt", NULL}; for (tag=0; tags[tag] != NULL; tag++) if (strcmp(tagname.c_str(), tags[tag]) == 0) Modified: trunk/matplotlib/ttconv/pprdrv_tt.cpp =================================================================== --- trunk/matplotlib/ttconv/pprdrv_tt.cpp 2007-08-02 21:32:30 UTC (rev 3668) +++ trunk/matplotlib/ttconv/pprdrv_tt.cpp 2007-08-02 22:49:01 UTC (rev 3669) @@ -107,7 +107,7 @@ ** is always 4 characters, though the last characters may be ** padding spaces. -----------------------------------------------------------------------*/ -BYTE *GetTable(struct TTFONT *font, const char *name) +BYTE *GetTable(struct TTFONT *font, char *name) { BYTE *ptr; ULONG x; @@ -654,7 +654,7 @@ */ void ttfont_sfnts(TTStreamWriter& stream, struct TTFONT *font) { - const char *table_names[]= /* The names of all tables */ + char *table_names[]= /* The names of all tables */ { /* which it is worth while */ "cvt ", /* to include in a Type 42 */ "fpgm", /* PostScript font. */ @@ -828,7 +828,7 @@ ** this array will instead convert PostScript character names ** to executable proceedures. --------------------------------------------------------------*/ -const char *Apple_CharStrings[]={ +char *Apple_CharStrings[]={ ".notdef",".null","nonmarkingreturn","space","exclam","quotedbl","numbersign", "dollar","percent","ampersand","quotesingle","parenleft","parenright", "asterisk","plus", "comma","hyphen","period","slash","zero","one","two", @@ -871,7 +871,7 @@ ** This routine is called by the one below. ** It is also called from pprdrv_tt2.c */ -const char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex) +char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex) { int GlyphIndex; static char temp[80]; @@ -1227,7 +1227,7 @@ i != glyph_ids.end(); ++i) { StringStreamWriter writer; tt_type3_charproc(writer, &font, *i); - const char* name = ttfont_CharStrings_getname(&font, *i); + char* name = ttfont_CharStrings_getname(&font, *i); dict.add_pair(name, writer.str().c_str()); } } Modified: trunk/matplotlib/ttconv/truetype.h =================================================================== --- trunk/matplotlib/ttconv/truetype.h 2007-08-02 21:32:30 UTC (rev 3668) +++ trunk/matplotlib/ttconv/truetype.h 2007-08-02 22:49:01 UTC (rev 3669) @@ -51,13 +51,13 @@ font_type_enum target_type; /* 42 or 3 for PS, or -3 for PDF */ ULONG numTables; /* number of tables present */ - const char *PostName; /* Font's PostScript name */ - const char *FullName; /* Font's full name */ - const char *FamilyName; /* Font's family name */ - const char *Style; /* Font's style string */ - const char *Copyright; /* Font's copyright string */ - const char *Version; /* Font's version string */ - const char *Trademark; /* Font's trademark string */ + char *PostName; /* Font's PostScript name */ + char *FullName; /* Font's full name */ + char *FamilyName; /* Font's family name */ + char *Style; /* Font's style string */ + char *Copyright; /* Font's copyright string */ + char *Version; /* Font's version string */ + char *Trademark; /* Font's trademark string */ int llx,lly,urx,ury; /* bounding box */ Fixed TTVersion; /* Truetype version number from offset table */ @@ -98,7 +98,7 @@ /* This is the one routine in pprdrv_tt.c that is */ /* called from pprdrv_tt.c. */ -const char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex); +char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex); void tt_type3_charproc(TTStreamWriter& stream, struct TTFONT *font, int charindex); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-03 17:27:22
|
Revision: 3670 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3670&view=rev Author: mdboom Date: 2007-08-03 10:27:20 -0700 (Fri, 03 Aug 2007) Log Message: ----------- Minor speed improvements from profiling. Fix kerning corruption issue when "shrinking" characters. Modified Paths: -------------- trunk/matplotlib/examples/mathtext_examples.py trunk/matplotlib/lib/matplotlib/mathtext.py Modified: trunk/matplotlib/examples/mathtext_examples.py =================================================================== --- trunk/matplotlib/examples/mathtext_examples.py 2007-08-02 22:49:01 UTC (rev 3669) +++ trunk/matplotlib/examples/mathtext_examples.py 2007-08-03 17:27:20 UTC (rev 3670) @@ -9,6 +9,7 @@ r'$100\%y\ x*y\ x/y x\$y$', r'$x\leftarrow y\ x\forall y\ x-y$', r'$x \sf x \bf x {\cal X} \rm x$', + r'$x\ x\,x\;x\quad x\qquad x\!x$', r'$\{ \rm braces \}$', r'$\left[\left\lfloor\frac{5}{\frac{\left(3\right)}{4}} y\right)\right]$', r'$\left(x\right)$', @@ -35,13 +36,29 @@ r"$f'$", r'$\frac{x_2888}{y}$', r"$\sqrt[3]{\frac{X_2}{Y}}=5$", + r"$\sqrt[5x\pi]{\prod^\frac{x}{2\pi^2}_\infty}$", r"$\sqrt[3]{x}=5$", r'$\frac{X}{\frac{X}{Y}}$', + # From UTR #25 + r"$W^{3\beta}_{\delta_1 \rho_1 \sigma_2} = U^{3\beta}_{\delta_1 \rho_1} + \frac{1}{8 \pi 2} \int^{\alpha_2}_{\alpha_2} d \alpha^\prime_2 \left[\frac{ U^{2\beta}_{\delta_1 \rho_1} - \alpha^\prime_2U^{1\beta}_{\rho_1 \sigma_2} }{U^{0\beta}_{\rho_1 \sigma_2}}\right]$", + r'$\mathcal{H} = \int d \tau (\epsilon E^2 + \mu H^2)$', r'$\widehat{abc}\widetilde{def}$' ] from pylab import * +def doall(): + for i, s in enumerate(stests): + print "%02d: %s" % (i, s) + plot([0,0,3], 'r') + x = arange(0.0, 3.0, 0.1) + + grid(True) + text(0.1, 1.6, s, fontsize=20, markup="tex") + + savefig('mathtext_example%02d' % i) + figure() + if '--latex' in sys.argv: fd = open("mathtext_examples.ltx", "w") fd.write("\\documentclass{article}\n") @@ -57,14 +74,4 @@ os.system("pdflatex mathtext_examples.ltx") else: - for i, s in enumerate(stests): - print "%02d: %s" % (i, s) - plot([1,2,3], 'r') - x = arange(0.0, 3.0, 0.1) - - grid(True) - text(1, 1.6, s, fontsize=20, markup="tex") - - savefig('mathtext_example%02d' % i) - figure() - + doall() Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-02 22:49:01 UTC (rev 3669) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-03 17:27:20 UTC (rev 3670) @@ -135,8 +135,9 @@ from sets import Set from unicodedata import category from warnings import warn -import numpy +from numpy import inf, isinf + from matplotlib import verbose from matplotlib.pyparsing import Literal, Word, OneOrMore, ZeroOrMore, \ Combine, Group, Optional, Forward, NotAny, alphas, nums, alphanums, \ @@ -554,7 +555,7 @@ def _get_offset(self, cached_font, glyph, fontsize, dpi): if cached_font.font.postscript_name == 'Cmex10': - return glyph.height/64.0/2 + 256.0/64.0 * dpi/72.0 + return glyph.height/64.0/2.0 + 256.0/64.0 * dpi/72.0 return 0. def _get_glyph(self, fontname, sym, fontsize): @@ -654,7 +655,7 @@ # This is a total hack, but it works for now if sym.startswith('\\big'): uniindex = get_unicode_index(sym[4:]) - fontsize *= INV_SHRINK_FACTOR + fontsize *= GROW_FACTOR else: warn("No TeX to unicode mapping for '%s'" % sym, MathTextWarning) @@ -848,7 +849,7 @@ # How much text shrinks when going to the next-smallest level SHRINK_FACTOR = 0.7 -INV_SHRINK_FACTOR = 1.0 / SHRINK_FACTOR +GROW_FACTOR = 1.0 / SHRINK_FACTOR # The number of different sizes of chars to use, beyond which they will not # get any smaller NUM_SIZE_LEVELS = 4 @@ -900,28 +901,22 @@ @135""" def __init__(self, width, height, depth): Node.__init__(self) - self.width = width - self.height = height - self.depth = depth + self.width = width + self.height = height + self.depth = depth def shrink(self): Node.shrink(self) if self.size < NUM_SIZE_LEVELS: - if self.width is not None: - self.width *= SHRINK_FACTOR - if self.height is not None: - self.height *= SHRINK_FACTOR - if self.depth is not None: - self.depth *= SHRINK_FACTOR + self.width *= SHRINK_FACTOR + self.height *= SHRINK_FACTOR + self.depth *= SHRINK_FACTOR def grow(self): Node.grow(self) - if self.width is not None: - self.width *= INV_SHRINK_FACTOR - if self.height is not None: - self.height *= INV_SHRINK_FACTOR - if self.depth is not None: - self.depth *= INV_SHRINK_FACTOR + self.width *= GROW_FACTOR + self.height *= GROW_FACTOR + self.depth *= GROW_FACTOR def render(self, x1, y1, x2, y2): pass @@ -992,12 +987,16 @@ Node.shrink(self) if self.size < NUM_SIZE_LEVELS: self.fontsize *= SHRINK_FACTOR - self._update_metrics() + self.width *= SHRINK_FACTOR + self.height *= SHRINK_FACTOR + self.depth *= SHRINK_FACTOR def grow(self): Node.grow(self) - self.fontsize *= INV_SHRINK_FACTOR - self._update_metrics() + self.fontsize *= GROW_FACTOR + self.width *= GROW_FACTOR + self.height *= GROW_FACTOR + self.depth *= GROW_FACTOR class Accent(Char): """The font metrics need to be dealt with differently for accents, since they @@ -1028,10 +1027,11 @@ self.glue_order = 0 # The order of infinity (0 - 3) for the glue def __repr__(self): - return '[%s <%d %d %d %d> %s]' % (self.__internal_repr__(), - self.width, self.height, - self.depth, self.shift_amount, - ' '.join([repr(x) for x in self.children])) + return '[%s <%.02f %.02f %.02f %.02f> %s]' % ( + self.__internal_repr__(), + self.width, self.height, + self.depth, self.shift_amount, + ' '.join([repr(x) for x in self.children])) def _determine_order(self, totals): """A helper function to determine the highest order of glue @@ -1069,8 +1069,8 @@ for child in self.children: child.grow() Box.grow(self) - self.shift_amount *= INV_SHRINK_FACTOR - self.glue_set *= INV_SHRINK_FACTOR + self.shift_amount *= GROW_FACTOR + self.glue_set *= GROW_FACTOR class Hlist(List): """A horizontal list of boxes. @@ -1131,7 +1131,7 @@ d = max(d, p.depth) elif isinstance(p, Box): x += p.width - if p.height is not None and p.depth is not None: + if not isinf(p.height) and not isinf(p.depth): s = getattr(p, 'shift_amount', 0.) h = max(h, p.height - s) d = max(d, p.depth + s) @@ -1167,7 +1167,7 @@ List.__init__(self, elements) self.vpack() - def vpack(self, h=0., m='additional', l=float(numpy.inf)): + def vpack(self, h=0., m='additional', l=float(inf)): """The main duty of vpack is to compute the dimensions of the resulting boxes, and to adjust the glue if one of those dimensions is pre-specified. @@ -1192,7 +1192,7 @@ if isinstance(p, Box): x += d + p.height d = p.depth - if p.width is not None: + if not isinf(p.width): s = getattr(p, 'shift_amount', 0.) w = max(w, p.width + s) elif isinstance(p, Glue): @@ -1234,7 +1234,7 @@ class Rule(Box): """A Rule node stands for a solid black rectangle; it has width, depth, and height fields just as in an Hlist. However, if any of these - dimensions is None, the actual value will be determined by running the + dimensions is inf, the actual value will be determined by running the rule up to the boundary of the innermost enclosing box. This is called a "running dimension." The width is never running in an Hlist; the height and depth are never running in a Vlist. @@ -1252,14 +1252,14 @@ thickness = state.font_output.get_underline_thickness( state.font, state.fontsize, state.dpi) height = depth = thickness * 0.5 - Rule.__init__(self, None, height, depth, state) + Rule.__init__(self, inf, height, depth, state) class Vrule(Rule): """Convenience class to create a vertical rule.""" def __init__(self, state): thickness = state.font_output.get_underline_thickness( state.font, state.fontsize, state.dpi) - Rule.__init__(self, thickness, None, None, state) + Rule.__init__(self, thickness, inf, inf, state) class Glue(Node): """Most of the information in this object is stored in the underlying @@ -1291,7 +1291,7 @@ Node.grow(self) if self.glue_spec.width != 0.: self.glue_spec = self.glue_spec.copy() - self.glue_spec.width *= INV_SHRINK_FACTOR + self.glue_spec.width *= GROW_FACTOR class GlueSpec(object): """@150, @151""" @@ -1379,6 +1379,9 @@ Node.__init__(self) self.width = width + def __repr__(self): + return "k%.02f" % self.width + def shrink(self): Node.shrink(self) if self.size < NUM_SIZE_LEVELS: @@ -1386,7 +1389,7 @@ def grow(self): Node.grow(self) - self.width *= INV_SHRINK_FACTOR + self.width *= GROW_FACTOR class SubSuperCluster(Hlist): """This class is a sort of hack to get around that fact that this @@ -1507,9 +1510,9 @@ rule_height = p.height rule_depth = p.depth rule_width = p.width - if rule_height is None: + if isinf(rule_height): rule_height = box.height - if rule_depth is None: + if isinf(rule_depth): rule_depth = box.depth if rule_height > 0 and rule_width > 0: self.cur_v = baseline + rule_depth @@ -1566,7 +1569,7 @@ rule_height = p.height rule_depth = p.depth rule_width = p.width - if rule_width is None: + if isinf(rule_width): rule_width = box.width rule_height += rule_depth if rule_height > 0 and rule_depth > 0: @@ -1822,7 +1825,7 @@ self._expression <<( non_math - + OneOrMore( + + ZeroOrMore( Suppress(math_delim) + math + Suppress(math_delim) @@ -2178,7 +2181,8 @@ else: if not isinstance(root, ParseResults): raise ParseFatalException( - "Can not parse root of radical. Only simple symbols are allowed.") + "Can not parse root of radical. " + "Only simple symbols are allowed in the root.") root = Hlist(root.asList()) root.shrink() root.shrink() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-06 18:52:10
|
Revision: 3676 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3676&view=rev Author: mdboom Date: 2007-08-06 11:52:07 -0700 (Mon, 06 Aug 2007) Log Message: ----------- Removed mathtext2. Fix horizontal centering in mathtext. Put all mathtext_examples on one plot. Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/examples/mathtext_examples.py trunk/matplotlib/lib/matplotlib/config/mplconfig.py trunk/matplotlib/lib/matplotlib/config/rcsetup.py trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc trunk/matplotlib/lib/matplotlib/rcsetup.py Removed Paths: ------------- trunk/matplotlib/examples/mathtext2_demo.py trunk/matplotlib/lib/matplotlib/mathtext2.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2007-08-06 18:50:00 UTC (rev 3675) +++ trunk/matplotlib/CHANGELOG 2007-08-06 18:52:07 UTC (rev 3676) @@ -1,3 +1,17 @@ +2007-08-06 Removed mathtext2 + +2007-07-31 Refactoring of distutils scripts. + - Will not fail on the entire build if an optional Python + package (e.g. Tkinter) is installed but its development + headers are not (e.g. tk-devel). Instead, it will + continue to build all other extensions. + - Provide an overview at the top of the output to display + what dependencies and their versions were found, and (by + extension) what will be built. + - Use pkg-config, when available, to find freetype2, since + this was broken on Mac OS-X when using MacPorts in a non- + standard location. + 2007-07-30 Reorganized configuration code to work with traited config objects. The new config system is located in the matplotlib.config package, but it is disabled by default. Deleted: trunk/matplotlib/examples/mathtext2_demo.py =================================================================== --- trunk/matplotlib/examples/mathtext2_demo.py 2007-08-06 18:50:00 UTC (rev 3675) +++ trunk/matplotlib/examples/mathtext2_demo.py 2007-08-06 18:52:07 UTC (rev 3676) @@ -1,89 +0,0 @@ -#!/usr/bin/env python -""" - -In order to use mathtext2, you must build matplotlib.ft2font. This is -built by default in the windows installer. - -For other platforms, edit setup.py and set - -BUILD_FT2FONT = True - -You have to put the following lines in your matplotlibrc file if you want to -enable mathtext2 globaly (not needed for running this example): - -mathtext.mathtext2: True # Needed to enable the new mathtext -mathtext.rm : FreeSerif.ttf -mathtext.it : FreeSerifItalic.ttf # Text italic -mathtext.tt : FreeMono.ttf # Typewriter (monospaced) -mathtext.mit : FreeSerifItalic.ttf # Math italic -mathtext.cal : FreeSansOblique.ttf # Caligraphic -mathtext.nonascii: FreeSerif.ttf # #Used for \sum, \infty etc. - -Note that "FreeSerif.ttf" etc. may be replaced by any font. Font files must be -in your system's font path. - -Only the first parameter must be set (mathtext2 uses BaKoMa fonts by -default, and they come packaged with matplotlib, so the above lines -override them) because mathtext2 is disabled by default. - -This demo assumes that you have FreeSerif.ttf installed. -You can get FreeSerif.ttf (and other files) from: -http://download.savannah.gnu.org/releases/freefont/ -if you are on windows. On linux, they are usually shipped by default. -FreeFonts are distributed under GPL. - -""" -# We override the default params -from matplotlib import rcParams -rcParams['mathtext.mathtext2'] = True - -# You can put other fonts to override the default ones -rcParams['mathtext.rm'] = 'FreeSerif.ttf' -rcParams['mathtext.it'] = 'FreeSerifItalic.ttf' -rcParams['mathtext.tt'] = 'FreeMono.ttf' -rcParams['mathtext.mit'] = 'FreeSerifItalic.ttf' -rcParams['mathtext.cal'] = 'FreeSansOblique.ttf' - -# This is used by mathtext2 to find chars with ord > 255 (Unicode characters) -rcParams['mathtext.nonascii'] = 'FreeSerif.ttf' -from pylab import * -subplot(111, axisbg='y') -plot([1,2,3], 'r') -x = arange(0.0, 3.0, 0.1) -grid(True) - -tex = r'$1+1\ u_{x^2_1}^{y_{-q_u}}$' -#text(0.5, 2., tex, fontsize=20) -#show() -#xlabel(r'$\Delta_i^j$', fontsize=20) -#ylabel(r'$\Delta_{i+1}^j$', fontsize=20) -#tex = r'$\cal{R}\prod_{i=\alpha_{i+1}}^\infty a_i\rm{sin}(2 \pi f x_i)$' -#tex = ur"$1^j_3$" -#tex = ur"$Tj_1j_jj_gT$" -#tex = ur"$F_1^1y_{1_{2_{3_2\sum_1^2{4}^6}}3}1_23$" -#tex = ur"$x_2{\cal TRALALA}\sum_1^2$" -#tex = ur"$a = x_2{\cal TRALALA}\sum_1^2$" -#tex = r'$K_{R osman dsfgs Tralala_{K_4^3}}X_1^1$' -#tex = ur"$Tutinjac\ fff\sin\exp$" -#tex = ur"$\sin\exp{\rm sin\ exp}$" -#tex = ur"$a^{\sin x}\sin b\sin(x/x), {\rm sin}(x/x){\rm sin\ }(x/x)$" -#tex = ur"$1\frac {\int_{-\infty}^\infty} 22$" -#tex = ur"$\rm a\vtext{Traktor}b$" -#tex = ur"$\frac{\int_{-\infty}^\infty} 2$" -#tex = ur"$1_\frac{\sum^2_{i_{23}=0}} 2678$" -#tex = ur"$1_{\frac{\sum^2_{i_{23}=0}}{\sum_{i=\frac94}^\infty} 345}678$" -text(0.5, 2., tex, fontsize=20) -tex = r'${\cal R}\prod_{i=\alpha_{i+1}}^\infty a_i\sin\exp(2 \pi f x_i)$' -#text(1, 1.9, tex, fontsize=20) -tex = ur"$F_1^1y_{1_{2_{3_2\sum_1^2{4}^6}}3}1_23$" -#text(1, 1.7, tex, fontsize=20) -tex = ur"$x = \sin(\sum_{i=0}^\infty y_i)$" -#text(1, 1.5, tex, fontsize=20) -#title(r'$\Delta_i^j \hspace{0.4} \rm{versus} \hspace{0.4} \Delta_{i+1}^j$', fontsize=20) - -savefig('mathtext_demo.png') -savefig('mathtext_demo.svg') -savefig('mathtext_demo.ps') - - -show() Modified: trunk/matplotlib/examples/mathtext_examples.py =================================================================== --- trunk/matplotlib/examples/mathtext_examples.py 2007-08-06 18:50:00 UTC (rev 3675) +++ trunk/matplotlib/examples/mathtext_examples.py 2007-08-06 18:52:07 UTC (rev 3676) @@ -20,8 +20,8 @@ r'$x_y^2$', r'$\prod_{i=\alpha_{i+1}}^\infty$', r'$x = \frac{x+\frac{5}{2}}{\frac{y+3}{8}}$', - r'$dz/dt \/ = \/ \gamma x^2 \/ + \/ {\rm sin}(2\pi y+\phi)$', - r'Foo: $\alpha_{i+1}^j \/ = \/ {\rm sin}(2\pi f_j t_i) e^{-5 t_i/\tau}$', + r'$dz/dt = \gamma x^2 + {\rm sin}(2\pi y+\phi)$', + r'Foo: $\alpha_{i+1}^j = {\rm sin}(2\pi f_j t_i) e^{-5 t_i/\tau}$', r'$\mathcal{R}\prod_{i=\alpha_{i+1}}^\infty a_i \sin(2 \pi f x_i)$', # r'$\bigodot \bigoplus {\sf R} a_i{\rm sin}(2 \pi f x_i)$', r'Variable $i$ is good', @@ -33,7 +33,7 @@ r"$\gamma = \frac{x=\frac{6}{8}}{y} \delta$", r'$\limsup_{x\to\infty}$', r'$\oint^\infty_0$', - r"$f'$", + r"$f^'$", r'$\frac{x_2888}{y}$', r"$\sqrt[3]{\frac{X_2}{Y}}=5$", r"$\sqrt[5x\pi]{\prod^\frac{x}{2\pi^2}_\infty}$", @@ -41,24 +41,29 @@ r'$\frac{X}{\frac{X}{Y}}$', # From UTR #25 r"$W^{3\beta}_{\delta_1 \rho_1 \sigma_2} = U^{3\beta}_{\delta_1 \rho_1} + \frac{1}{8 \pi 2} \int^{\alpha_2}_{\alpha_2} d \alpha^\prime_2 \left[\frac{ U^{2\beta}_{\delta_1 \rho_1} - \alpha^\prime_2U^{1\beta}_{\rho_1 \sigma_2} }{U^{0\beta}_{\rho_1 \sigma_2}}\right]$", - r'$\mathcal{H} = \int d \tau (\epsilon E^2 + \mu H^2)$', - r'$\widehat{abc}\widetilde{def}$' + r'$\mathcal{H} = \int d \tau \left(\epsilon E^2 + \mu H^2\right)$', + r'$\widehat{abc}\widetilde{def}$', + r'$\Gamma \Delta \Theta \Lambda \Xi \Pi \Sigma \Upsilon \Phi \Psi \Omega$', + r'$\alpha \beta \gamma \delta \epsilon \zeta \eta \theta \iota \lambda \mu \nu \xi \pi \kappa \rho \sigma \tau \upsilon \phi \chi \psi$' ] from pylab import * def doall(): - for i, s in enumerate(stests): + tests = stests + + figure(figsize=(8, (len(tests) * 1) + 2)) + plot([0, 0], 'r') + grid(False) + axis([0, 3, -len(tests), 0]) + yticks(arange(len(tests)) * -1) + for i, s in enumerate(tests): print "%02d: %s" % (i, s) - plot([0,0,3], 'r') - x = arange(0.0, 3.0, 0.1) + text(0.1, -i, s, fontsize=20, markup="tex") - grid(True) - text(0.1, 1.6, s, fontsize=20, markup="tex") + savefig('mathtext_example') + figure() - savefig('mathtext_example%02d' % i) - figure() - if '--latex' in sys.argv: fd = open("mathtext_examples.ltx", "w") fd.write("\\documentclass{article}\n") Modified: trunk/matplotlib/lib/matplotlib/config/mplconfig.py =================================================================== --- trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2007-08-06 18:50:00 UTC (rev 3675) +++ trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2007-08-06 18:52:07 UTC (rev 3676) @@ -153,21 +153,13 @@ class text(TConfig): color = T.Trait('black',mplT.ColorHandler()) usetex = T.false + markup = T.Trait('plain', 'tex') class latex(TConfig): unicode = T.false preamble = T.ListStr([]) dvipnghack = T.false - class math(TConfig): - mathtext2 = T.false - rm = T.Trait('cmr10.ttf') - it = T.Trait('cmmi10.ttf') - tt = T.Trait('cmtt10.ttf') - mit = T.Trait('cmmi10.ttf') - cal = T.Trait('cmsy10.ttf') - nonascii = T.Trait('cmex10.ttf') - class axes(TConfig): hold = T.Trait(True, mplT.BoolHandler()) facecolor = T.Trait('white', mplT.ColorHandler()) @@ -336,6 +328,7 @@ 'text.latex.unicode' : (self.tconfig.text.latex, 'unicode'), 'text.latex.preamble' : (self.tconfig.text.latex, 'preamble'), 'text.dvipnghack' : (self.tconfig.text.latex, 'dvipnghack'), + 'text.markup' : (self.tconfig.text.markup, 'markup'), 'image.aspect' : (self.tconfig.image, 'aspect'), 'image.interpolation' : (self.tconfig.image, 'interpolation'), @@ -429,14 +422,6 @@ 'svg.image_noscale' : (self.tconfig.backend.svg, 'image_noscale'), 'svg.embed_char_paths' : (self.tconfig.backend.svg, 'embed_chars'), - # mathtext settings - 'mathtext.mathtext2' : (self.tconfig.text.math, 'mathtext2'), - 'mathtext.rm' : (self.tconfig.text.math, 'rm'), - 'mathtext.it' : (self.tconfig.text.math, 'it'), - 'mathtext.tt' : (self.tconfig.text.math, 'tt'), - 'mathtext.mit' : (self.tconfig.text.math, 'mit'), - 'mathtext.cal' : (self.tconfig.text.math, 'cal'), - 'mathtext.nonascii' : (self.tconfig.text.math, 'nonascii'), } def __setitem__(self, key, val): Modified: trunk/matplotlib/lib/matplotlib/config/rcsetup.py =================================================================== --- trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2007-08-06 18:50:00 UTC (rev 3675) +++ trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2007-08-06 18:52:07 UTC (rev 3676) @@ -448,16 +448,6 @@ 'svg.embed_char_paths' : [False, validate_bool], # True to save #all characters as paths in the SVG - # mathtext settings - 'mathtext.mathtext2' : [False, validate_bool], # Needed to enable Unicode - # fonts used by mathtext. These ship with matplotlib - 'mathtext.rm' : ['cmr10.ttf', str], # Roman (normal) - 'mathtext.it' : ['cmmi10.ttf', str], # Italic - 'mathtext.tt' : ['cmtt10.ttf', str], # Typewriter (monospaced) - 'mathtext.mit' : ['cmmi10.ttf', str], # Math italic - 'mathtext.cal' : ['cmsy10.ttf', str], # Caligraphic - 'mathtext.nonascii' : ['cmex10.ttf', str], # All other nonascii fonts - } if __name__ == '__main__': Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-06 18:50:00 UTC (rev 3675) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-06 18:52:07 UTC (rev 3676) @@ -246,7 +246,7 @@ def render_glyph(self, ox, oy, info): info.font.draw_glyph_to_bitmap( - int(ox), int(oy - info.metrics.ymax), info.glyph) + ox, oy - info.metrics.ymax, info.glyph) def render_rect_filled(self, x1, y1, x2, y2): font = self.fonts_object.get_fonts()[0] @@ -297,7 +297,7 @@ def render_glyph(self, ox, oy, info): filename = info.font.fname oy = self.height - oy + info.offset - + self.pswriter.append(('glyph', ox, oy, filename, info.fontsize, info.num)) def render_rect_filled(self, x1, y1, x2, y2): @@ -865,7 +865,7 @@ # get any smaller NUM_SIZE_LEVELS = 4 # Percentage of x-height of additional horiz. space after sub/superscripts -SCRIPT_SPACE = 0.3 +SCRIPT_SPACE = 0.2 # Percentage of x-height that sub/superscripts drop below the baseline SUBDROP = 0.3 # Percentage of x-height that superscripts drop below the baseline @@ -873,7 +873,7 @@ # Percentage of x-height that subscripts drop below the baseline SUB1 = 0.0 # Percentage of x-height that superscripts are offset relative to the subscript -DELTA = 0.25 +DELTA = 0.18 class MathTextWarning(Warning): pass @@ -1101,19 +1101,20 @@ list in the correct way.""" new_children = [] num_children = len(self.children) - for i in range(num_children): - elem = self.children[i] - if i < num_children - 1: - next = self.children[i + 1] - else: - next = None + if num_children: + for i in range(num_children): + elem = self.children[i] + if i < num_children - 1: + next = self.children[i + 1] + else: + next = None - new_children.append(elem) - kerning_distance = elem.get_kerning(next) - if kerning_distance != 0.: - kern = Kern(kerning_distance) - new_children.append(kern) - self.children = new_children + new_children.append(elem) + kerning_distance = elem.get_kerning(next) + if kerning_distance != 0.: + kern = Kern(kerning_distance) + new_children.append(kern) + self.children = new_children def hpack(self, w=0., m='additional'): """The main duty of hpack is to compute the dimensions of the @@ -1372,9 +1373,15 @@ class HCentered(Hlist): """A convenience class to create an Hlist whose contents are centered within its enclosing box.""" - def __init__(self, elements): + def __init__(self, elements, is_accent = False): + self.is_accent = is_accent Hlist.__init__(self, [SsGlue()] + elements + [SsGlue()]) + def kern(self): + Hlist.kern(self) + if not self.is_accent and isinstance(self.children[-2], Kern): + self.children = self.children[:-2] + [SsGlue()] + class VCentered(Hlist): """A convenience class to create an Vlist whose contents are centered within its enclosing box.""" @@ -1982,7 +1989,7 @@ else: accent = Accent(self._accent_map[accent], state) shift_amount = accent._metrics.xmin - centered = HCentered([accent]) + centered = HCentered([accent], is_accent=True) centered.hpack(sym.width, 'exactly') centered.shift_amount = shift_amount return Vlist([ Deleted: trunk/matplotlib/lib/matplotlib/mathtext2.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext2.py 2007-08-06 18:50:00 UTC (rev 3675) +++ trunk/matplotlib/lib/matplotlib/mathtext2.py 2007-08-06 18:52:07 UTC (rev 3676) @@ -1,1038 +0,0 @@ -r""" -Supported commands: -------------------- - * _, ^, to any depth - * commands for typesetting functions (\sin, \cos etc.), - * commands for changing the current font (\rm, \cal etc.), - * Space/kern commands "\ ", \thinspace - * \frac - -Small TO-DO's: --------------- - * Display braces etc. \} not working (displaying wierd characters) etc. - * better placing of sub/superscripts. F_1^1y_{1_{2_{3_{4}^3}}3}1_23 - * implement crampedness (or is it smth. else?). y_1 vs. y_1^1 - * add better italic correction. F^1 - * implement other space/kern commands - -TO-DO's: --------- - * \over, \above, \choose etc. - * Add support for other backends - -""" -import os -from math import fabs, floor, ceil - -from matplotlib import get_data_path, rcParams -from matplotlib._mathtext_data import tex2uni -from matplotlib.ft2font import FT2Font, KERNING_DEFAULT -from matplotlib.font_manager import findSystemFonts -from copy import deepcopy -from matplotlib.cbook import Bunch - -_path = get_data_path() -faces = ('mit', 'rm', 'tt', 'cal', 'nonascii') - -filenamesd = {} -fonts = {} - -# Filling the above dicts -for face in faces: - # The filename without the path - barefname = rcParams['mathtext.' + face] - base, ext = os.path.splitext(barefname) - if not ext: - ext = '.ttf' - barefname = base + ext - # First, we search for the font in the system font dir - for fname in findSystemFonts(fontext=ext[1:]): - if fname.endswith(barefname): - filenamesd[face] = str(fname) - break - # We check if the for loop above had success. If it failed, we try to - # find the font in the mpl-data dir - if not face in filenamesd: - fontdirs = [os.path.join(_path,'fonts','afm'), - os.path.join(_path,'fonts','ttf')] - for fontdir in fontdirs: - fname = os.path.join(fontdir, barefname) - if os.path.exists( fname ): - filenamesd[face] = fname - break - # Display a useful message when the fontfile is not found. - # TO-DO: Maybe this should just throw a warning to the user? - try: - fonts[face] = FT2Font(filenamesd[face]) - except KeyError: - msg = "Can't find the font file for the '%s' face"%face - raise KeyError(msg) - -svg_elements = Bunch(svg_glyphs=[], svg_lines=[]) - -esc_char = '\\' -# Grouping delimiters -begin_group_char = '{' -end_group_char = '}' -dec_delim = '.' -word_delim = ' ' -mathstyles = ["display", "text", "script", "scriptscript"] -modes = ["mathmode", "displaymathmode"] - -# Commands -scripts = ("_", "^") -functions = ("sin", "tan", "cos", "exp", "arctan", "arccos", "arcsin", "cot", - "lim", "log") -reserved = ("{", "}", "%", "$", "#", "~") -# Commands that change the environment (in the current scope) -setters = faces -# Maximum number of nestings (groups within groups) -max_depth = 10 - -#~ environment = { -#~ "mode": "mathmode", -#~ "mathstyle" : "display", -#~ "cramped" : False, -#~ # We start with zero scriptdepth (should be incremented by a Scripted -#~ # instance) -#~ "scriptdepth" : 0, -#~ "face" : None, -#~ "fontsize" : 12, -#~ "dpi" : 100, -#~ } - - -# _textclass can be unicode or str. -_textclass = unicode - - -# Exception classes -class TexParseError(Exception): - pass - -# Helper classes -class Scriptfactors(dict): - """Used for returning the factor with wich you should multiply the - fontsize to get the font size of the script - - """ - _scriptfactors = { - 0 : 1, # Normal text - 1: 0.8, # Script - 2: 0.6, # Scriptscript - # For keys > 3 returns 0.6 - } - - def __getitem__(self, key): - if not isinstance(key, int): - raise KeyError("Integer value needed for scriptdepth") - if key < 0: - raise KeyError("scriptdepth must be positive") - if key in self._scriptfactors: - return self._scriptfactors[key] - else: - # Maximum depth of scripts is 2 (scriptscript) - return self._scriptfactors[2] - -scriptfactors = Scriptfactors() - - -class Environment: - """Class used for representing the TeX environment variables""" - def __init__(self): - self.mode = "mathmode" - self.mathstyle = "display" - self.cramped = False - # We start with zero scriptdepth (should be incremented by a Scripted - # instance) - self.scriptdepth = 0 - self.face = None - self.fontsize = 12 - self.dpi = 100 - self.output = "AGG" - - def copy(self): - return deepcopy(self) - -# The topmost environment -environment = Environment() - - -# Helper functions used by the renderer -def get_frac_bar_height(env): - # TO-DO: Find a better way to calculate the height of the rule - c = Char(env, ".") - return (c.ymax - c.ymin)/2 - -def get_font(env): - env = env.copy() - # TO-DO: Perhaps this should be done somewhere else - fontsize = env.fontsize * scriptfactors[env.scriptdepth] - dpi = env.dpi - if not env.face: - env.face = "rm" - font = fonts[env.face] - - font.set_size(fontsize, dpi) - return font - #~ font = FT2Font(filenamesd[face]) - #~ if fonts: - #~ fonts[max(fonts.keys()) + 1] = font - #~ else: - #~ fonts[1] = font - -def infer_face(env, item): - if item.isalpha(): - if env.mode == "mathmode" and item < "z": - face = "mit" - else: - # TO-DO: Perhaps change to 'rm' - face = "nonascii" - elif item.isdigit(): - face = "rm" - elif ord(item) < 256: - face = "rm" - else: - face = "nonascii" - return face - -def get_space(env): - _env = env.copy() - if not _env.face: - _env.face = "rm" - space = Char(_env, " ") - return space - -def get_kern(first, second): - # TO-DO: Something's wrong - if isinstance(first,Char) and isinstance(second, Char): - if first.env.__dict__ == second.env.__dict__: - font = get_font(first.env) - advance = -font.get_kerning(first.uniindex, second.uniindex, - KERNING_DEFAULT)/64.0 - #print first.char, second.char, advance - return Kern(first.env, advance) - else: - return Kern(first.env, 0) - else: - return Kern(first.env, 0) - - -# Classes used for renderering - -# Base rendering class -class Renderer: - """Abstract class that implements the rendering methods""" - def __init__(self, env): - # We initialize all the values to 0.0 - self.xmin, self.ymin, self.xmax, self.ymax = (0.0,)*4 - self.width, self.height = (0.0,)*2 - (self.hadvance, self.hbearingx, self.hbearingy, - self.hdescent)= (0.0,)*4 - (self.vadvance, self.vbearingx, self.vbearingy)= (0.0,)*3 - self.env = env - - def hrender(self, x, y): - pass - - def vrender(self, x, y): - # We reuse hrender. This can be used by all subclasses of Renderer - y += self.vbearingy + self.hbearingy - x -= -self.vbearingx + self.hbearingx - self.hrender(x, y) - -# Primitive rendering classes -class Char(Renderer): - """A class that implements rendering of a single character.""" - def __init__(self, env, char, uniindex=None): - #Renderer.__init__(self, env) - self.env = env - # uniindex is used to override ord(char) (needed on platforms where - # there is only BMP support for unicode, i.e. windows) - msg = "A char (string with length == 1) is needed" - if isinstance(_textclass(char), _textclass) and len(char) == 1: - self.char = char - else: - raise ValueError(msg) - if not uniindex: - self.uniindex = ord(char) - else: - if isinstance(uniindex, int): - self.uniindex = uniindex - else: - raise ValueError("uniindex must be an int") - #print self.env.face, filenamesd - # TO-DO: This code is needed for BaKoMa fonts. To be removed when - # mathtext migrates to completely unicode fonts - if self.env.face == "rm" and filenamesd["rm"].endswith("cmr10.ttf"): - _env = self.env.copy() - if self.char in ("{", "}"): - _env.face = "cal" - font = get_font(_env) - if self.char == "{": - index = 118 - elif self.char == "}": - index = 119 - glyph = font.load_char(index) - else: - font = get_font(self.env) - glyph = font.load_char(self.uniindex) - else: - font = get_font(self.env) - glyph = font.load_char(self.uniindex) - self.glyph = glyph - self.xmin, self.ymin, self.xmax, self.ymax = [ - val/64.0 for val in self.glyph.bbox] - - self.width = self.xmax - self.xmin#glyph.width/64.0 - self.height = self.ymax - self.ymin#glyph.height/64.0 - # Horizontal values - self.hadvance = glyph.horiAdvance/64.0 - self.hbearingx = glyph.horiBearingX/64.0 - self.hbearingy = glyph.horiBearingY/64.0 - # Vertical values - self.vadvance = glyph.vertAdvance/64.0 - self.vbearingx = glyph.vertBearingX/64.0 - self.vbearingy = glyph.vertBearingY/64.0 - - def hrender(self, x, y): - #y -= self.ymax - #y -= (self.height - self.hbearingy) - #print x, y - font = get_font(self.env) - output = self.env.output - if output == "AGG": - x += self.hbearingx - y -= self.hbearingy - font.draw_glyph_to_bitmap(x, y, self.glyph) - elif output == "SVG": - familyname = font.get_sfnt()[(1,0,0,1)] - thetext = unichr(self.uniindex) - thetext.encode('utf-8') - fontsize = self.env.fontsize * scriptfactors[self.env.scriptdepth] - svg_elements.svg_glyphs.append((familyname, fontsize,thetext, x, y, - Bunch(advance=self.hadvance))) # last was originaly metrics (in old mathtext) - - -class Kern(Renderer): - """Class that implements the rendering of a Kern.""" - - def __init__(self, env, hadvance): - Renderer.__init__(self, env) - self.width = hadvance - self.hadvance = hadvance - - def __repr__(self): - return "Kern(%s, %s)"%(self.env, self.hadvance) - -class Line(Renderer): - """Class that implements the rendering of a line.""" - - def __init__(self, env, width, height): - Renderer.__init__(self, env) - self.ymin = -height/2. - self.xmax = width - self.ymax = height/2. - - self.width = width - self.height = height - self.hadvance = width - self.hbearingy = self.ymax - # vertical - self.vadvance = height - self.vbearingx = - width/2.0 - - def hrender(self, x, y): - font = get_font(self.env) - coords = (x + self.xmin, y + self.ymin, x + self.xmax, - y + self.ymax) - #print coords - #print "\n".join(repr(self.__dict__).split(",")) - if self.env.output == "AGG": - coords = (coords[0]+2, coords[1]-1, coords[2]-2, - coords[3]-1) - #print coords - font.draw_rect_filled(*coords) - elif self.env.output == "SVG": - svg_elements.svg_lines.append(coords) - #~ familyname = font.get_sfnt()[(1,0,0,1)] - #~ svg_elements.svg_glyphs.append((familyname, self.env.fontsize, - #~ "---", x,y, None)) - - -# Complex rendering classes -class Hbox(Renderer): - """A class that corresponds to a TeX hbox.""" - def __init__(self, env, texlist=[]): - Renderer.__init__(self, env) - self.items = texlist - if not self.items: - # empty group - return - previous = None - for item in self.items: - # Checking for kerning - if previous: - kern = get_kern(previous, item) - item.hadvance += kern.hadvance - self.hbearingy = max((item.hbearingy, self.hbearingy)) - self.ymax = max((item.ymax, self.ymax)) - if self.ymin == 0: - self.ymin = item.ymin - else: - self.ymin = min((item.ymin, self.ymin)) - self.hadvance += item.hadvance - # vertical - self.vadvance = max((item.vadvance, self.vadvance)) - if self.vbearingy == 0: - self.vbearingy = item.vbearingy - else: - self.vbearingy = min(item.vbearingy, self.vbearingy) - previous = item - first = self.items[0] - self.hbearingx = 0#first.hbearingx - self.xmin = 0#first.xmin - - last = self.items[-1] - self.xmax = self.hadvance# + fabs(last.hadvance - last.xmax) - self.xmax -= first.hbearingx - self.width = self.xmax - self.xmin - self.height = self.ymax - self.ymin - # vertical - self.vbearingx = - self.width/2.0 - - def hrender(self, x, y): - for item in self.items: - item.hrender(x, y) - x += item.hadvance - -# TO-DO -class Vbox(Renderer): - """A class representing a vertical box. ref is the index of the texlist - element whose origin will be used as the vbox origin. The default is - ref=-1. If ref is None, then ref is set to be the middle index (if the - number of items in the list is even, a new list element is inserted (as - Kern(0)) to make the list odd). - The box is rendered top down - the last element of the list is rendered - at the bottom. - - """ - def __init__(self, env, texlist=[], ref=None): - if ref == None: - if not len(texlist)%2: - texlist = texlist.insert(len(texlist)/2,Kern(env, 0)) - ref = len(texlist)/2 - if ref < 0: - ref = len(texlist) + ref - Renderer.__init__(self, env) - - self.items = texlist - if not self.items: - return - - for i, item in enumerate(self.items): - if i == 0: - self.vbearingy = item.vbearingy - if i == ref: - # ymax is determined by the reference item - if self.vadvance == 0: - #self.ymax = item.ymax - self.hbearingy = item.hbearingy - else: - #self.ymax = self.vadvance + item.ymax + item.vbearingy - self.hbearingy = self.vadvance + item.hbearingy +\ - item.vbearingy - self.width = max(self.width, item.width) - if self.width < item.width: - self.width = item.width - self.hbearingx = item.hbearingx - self.hadvance = max(self.hadvance, item.hadvance) - self.vbearingx = min(self.vbearingx, item.vbearingx) - self.vadvance += item.vadvance - if i == len(self.items) - 1: - # last item - if i == 0: - self.ymin = item.ymin - else: - _overlap = item.vadvance - item.height -item.vbearingy - self.ymin = -(self.vadvance - _overlap - self.hbearingy) - self.xmin = self.hbearingx - self.xmax = self.xmin + self.width - - self.ymax = self.hbearingy - self.height = self.ymax - self.ymin - - def hrender(self, x, y): - # We reuse vrender. - print "H" - y -= self.vbearingy + self.hbearingy - x += -self.vbearingx + self.hbearingx - self.vrender(x, y) - - def vrender(self, x, y): - print "V" - #print "\n".join(repr(self.__dict__).split(",")) - for item in self.items: - for key in item.__dict__: - try: - print key, getattr(self, key), getattr(item, key) - except AttributeError: - pass - #print "\n".join(repr(item.__dict__).split(",")) - item.vrender(x, y) - y += item.vadvance - -class Scripted(Renderer): - """Used for creating elements that have sub/superscripts""" - def __init__(self, env, nuc=None, type="ord", sub=None, - sup=None): - Renderer.__init__(self, env) - if not nuc: - nuc = Hbox([]) - if not sub: - sub = Hbox([]) - if not sup: - sup = Hbox([]) - self.nuc = nuc - self.sub = sub - self.sup = sup - self.type = type - # Heuristics for figuring out how much the subscripts origin has to be - # below the origin of the nucleus (the descent of the letter "j"). - # TO-DO: Change with a better alternative. Not working: F_1^1y_1 - c = Char(env, "j") - C = Char(env, "M") - - self.subpad = c.height - c.hbearingy - # If subscript is complex (i.e. a large Hbox - fraction etc.) - # we have to aditionaly lower the subscript - if sub.ymax > (C.height/2.1 + self.subpad): - self.subpad = sub.ymax - C.height/2.1 - - #self.subpad = max(self.subpad) - #self.subpad = 0.5*sub.height - # Similar for the superscript - self.suppad = max(nuc.height/1.9, C.ymax/1.9) - sup.ymin# - C.hbearingy - - - #self.hadvance = nuc.hadvance + max((sub.hadvance, sup.hadvance)) - - self.xmin = nuc.xmin - - self.xmax = max(nuc.hadvance, nuc.hbearingx + nuc.width) +\ - max((sub.hadvance, sub.hbearingx + sub.width, - sup.hadvance, sup.hbearingx + sup.width))# - corr - - self.ymin = min(nuc.ymin, -self.subpad + sub.ymin) - - self.ymax = max((nuc.ymax, self.suppad + sup.hbearingy)) - - # The bearing of the whole element is the bearing of the nucleus - self.hbearingx = nuc.hbearingx - self.hadvance = self.xmax - # Heruistics. Feel free to change - self.hbearingy = self.ymax - - self.width = self.xmax - self.xmin - self.height = self.ymax - self.ymin - # vertical - self.vadvance = self.height - self.vbearingx = - self.width/2.0 - - def hrender(self, x, y): - nuc, sub, sup = self.nuc, self.sub, self.sup - nx = x - ny = y - - subx = x + max(nuc.hadvance, nuc.hbearingx + nuc.width)# + sub.hbearingx - suby = y + self.subpad# - subfactor*self.env.fontsize - - supx = x + max(nuc.hadvance, nuc.hbearingx + nuc.width)# + sup.hbearingx - supy = y - self.suppad# + 10#subfactor*self.env.fontsize - - self.nuc.hrender(nx, ny) - self.sub.hrender(subx, suby) - self.sup.hrender(supx, supy) - - def __repr__(self): - tmp = [repr(i) for i in [self.env, self.nuc, self.type, - self.sub, self.sup]] - tmp = tuple(tmp) - return "Scripted(env=%s,nuc=%s, type=%s, \ -sub=%s, sup=%s)"%tmp - - -class Fraction(Renderer): - """A class for rendering a fraction.""" - - def __init__(self, env, num, den): - Renderer.__init__(self, env) - self.numer = num - self.denom = den - - # TO-DO: Find a better way to implement the fraction bar - self.pad = get_frac_bar_height(self.env) - pad = self.pad - self.bar = Line(env.copy(), max(num.width, den.width) + 2*pad, pad) - #~ self.bar.hbearingx = pad - #~ self.bar.hadvance = self.bar.width + 2*pad - #~ self.bar.hbearingy = pad + pad - - self.xmin = 0 - #self.xmax = self.bar.hadvance - self.xmax = self.bar.width# + 2*pad - - self.ymin = -(2*pad + den.height) - self.ymax = 2*pad + num.height - # The amount by which we raise the bar (the whole fraction) - # of the bottom (origin) - # TO-DO: Find a better way to implement it - _env = env.copy() - _env.face = "rm" - c = Char(_env, "+") - self.barpad = 1./2.*(c.ymax-c.ymin) + c.ymin - self.ymin += self.barpad - self.ymax += self.barpad - - self.width = self.xmax - self.xmin - self.height = self.ymax - self.ymin - #print self.width, self.height - - #self.hbearingx = pad - self.hbearingx = 0 - self.hbearingy = self.ymax - #self.hadvance = self.bar.hadvance - self.hadvance = self.xmax - # vertical - self.vbearingx = - self.width/2.0 - self.vbearingy = num.vbearingy - self.vadvance = self.height + num.vbearingy + (den.vadvance + den.ymin) - - def hrender(self, x, y): - y -= self.barpad - pad = self.pad - #print self.bar.xmax, self.bar.xmin, self.bar.ymin, self.bar.ymax - self.bar.hrender(x, y) - - nx = x - self.numer.hbearingx + (self.width - self.numer.width)/2. - ny = y - 2*pad - (self.numer.height - self.numer.ymax) - self.numer.hrender(nx, ny) - - dx = x - self.denom.hbearingx+ (self.width - self.denom.width)/2. - dy = y + 2*pad + self.denom.hbearingy - self.denom.hrender(dx, dy) - - - - -# Helper functions used by the parser -def parse_tex(texstring): - texstring = normalize_tex(texstring) - _parsed = to_list(texstring) - #_parsed = Hbox(_parsed) - return _parsed - -def remove_comments(texstring): - # TO-DO - return texstring - -def group_split(texstring): - """Splits the string into three parts based on the grouping delimiters, - and returns them as a list. - """ - if texstring == begin_group_char + end_group_char: - return '', [], '' - length = len(texstring) - i = texstring.find(begin_group_char) - if i == -1: - return texstring, '', '' - pos_begin = i - count = 1 - num_groups = 0 - while count != 0: - i = i + 1 - # First we check some things - if num_groups > max_depth: - message = "Maximum number of nestings reached. Too many groups" - raise TexParseError(message) - if i == length: - message = "Group not closed properly" - raise TexParseError(message) - - if texstring[i] == end_group_char: - count -= 1 - elif texstring[i] == begin_group_char: - num_groups += 1 - count += 1 - before = texstring[:pos_begin] - if pos_begin + 1 == i: - grouping = [] - else: - grouping = texstring[pos_begin + 1:i] - after = texstring[i + 1:] - return before, grouping, after - -def break_up_commands(texstring): - """Breaks up a string (mustn't contain any groupings) into a list - of commands and pure text. - """ - result = [] - if not texstring: - return result - _texstrings = texstring.split(esc_char) - for i, _texstring in enumerate(_texstrings): - _command, _puretext = split_command(_texstring) - if i == 0 and _texstrings[0]: - # Case when the first command is a not a command but text - result.extend([c for c in _command]) - result.extend(_puretext) - continue - if _command: - result.append(esc_char + _command) - if _puretext: - if _puretext[0] == word_delim: - _puretext = _puretext[1:] - result.extend(_puretext) - return result - -def split_command(texstring): - """Splits a texstring into a command part and a pure text (as a list) part - - """ - if not texstring: - return "", [] - _puretext = [] - _command, _rest = get_first_word(texstring) - if not _command: - _command = texstring[0] - _rest = texstring[1:] - _puretext = [c for c in _rest] - #~ while True: - #~ _word, _rest = get_first_word(_rest) - #~ if _word: - #~ _puretext.append(_word) - #~ if _rest: - #~ _puretext.extend(_rest[0]) - #~ if len(_rest) == 1: - #~ break - #~ _rest = _rest[1:] - #~ else: - #~ break - return _command, _puretext - -def get_first_word(texstring): - _word = "" - i = 0 - _length = len(texstring) - if _length == 0: - return "", "" - if texstring[0].isalpha(): - while _length > i and texstring[i].isalpha(): - _word += texstring[i] - i = i + 1 - elif texstring[0].isdigit(): - while _length > i and (texstring[i].isdigit()): - _word += texstring[i] - i = i + 1 - - return _word, texstring[i:] - -def to_list(texstring): - """Parses the normalized tex string and returns a list. Used recursively. - """ - result = [] - if not texstring: - return result - # Checking for groupings: begin_group_char...end_group_char - before, grouping, after = group_split(texstring) - #print "Before: ", before, '\n', grouping, '\n', after - - if before: - result.extend(break_up_commands(before)) - if grouping or grouping == []: - result.append(to_list(grouping)) - if after: - result.extend(to_list(after)) - - return result - -def normalize_tex(texstring): - """Normalizes the whole TeX expression (that is: prepares it for - parsing)""" - texstring = remove_comments(texstring) - # Removing the escaped escape character (replacing it) - texstring = texstring.replace(esc_char + esc_char, esc_char + 'backslash ') - - # Removing the escaped scope/grouping characters - texstring = texstring.replace(esc_char + begin_group_char, esc_char + 'lbrace ') - texstring = texstring.replace(esc_char + end_group_char, esc_char + 'rbrace ') - - # Now we should have a clean expression, so we check if all the groupings - # are OK (every begin_group_char should have a matching end_group_char) - # TO-DO - - # Replacing all space-like characters with a single space word_delim - texstring = word_delim.join(texstring.split()) - - # Removing unnecessary white space - texstring = word_delim.join(texstring.split()) - return texstring - -def is_command(item): - try: - return item.startswith(esc_char) - except AttributeError: - return False - - - - -# Main parser functions -def handle_tokens(texgroup, env, box=Hbox): - """Scans the entire (tex)group to handle tokens. Tokens are other groups, - commands, characters, kerns etc. Used recursively. - - """ - result = [] - # So we're sure that nothing changes the outer environment - env = env.copy() - while texgroup: - item = texgroup.pop(0) - #print texgroup, type(texgroup) - #print env.face, type(item), repr(item) - if isinstance(item, list): - appendix = handle_tokens(item, env.copy()) - elif item in scripts: - sub, sup, texgroup = handle_scripts(item, texgroup, env.copy()) - try: - nuc = result.pop() - except IndexError: - nuc = Hbox([]) - appendix = Scripted(env.copy(), nuc=nuc, sub=sub, sup=sup) - elif is_command(item): - command = item.strip(esc_char) - texgroup, env = handle_command(command, texgroup, env.copy(), - allowsetters=True) - continue - elif isinstance(item, _textclass): - if env.mode == "mathmode": - if item == word_delim: - # Disregard space in mathmode - continue - elif item == "-": - # load the math minus sign - item = u"\u2212" - uniindex = ord(item) - appendix = handle_char(uniindex, env.copy()) - else: - appendix = item - result.append(appendix) - return box(env.copy(),result) - -def handle_command(command, texgroup, env, allowsetters=False): - """Handles TeX commands that don't have backward propagation, and - aren't setting anything in the environment. - - """ - # First we deal with setters - commands that change the - # environment of the current group (scope) - if command in setters: - if not allowsetters: - raise TexParseError("Seter not allowed here") - if command in faces: - env.face = command - else: - raise TexParseError("Unknown setter: %s%s"%(esc_char, command)) - return texgroup, env - elif command == "frac": - texgroup, args = get_args(command, texgroup, env.copy(), 2) - num, den = args - frac = Fraction(env=env, num=num, den=den) - appendix = frac - elif command in functions: - _tex = "%srm %sthinspace %s"%(esc_char, esc_char, command) - appendix = handle_tokens(parse_tex(_tex), env.copy()) - elif command in (" "): - space = get_space(env) - appendix = Kern(env, space.hadvance) - elif command == "thinspace": - #print command - space = get_space(env) - appendix = Kern(env, 1/2. * space.hadvance) - elif command in reserved: - uniindex = ord(command) - appendix = handle_char(uniindex, env.copy()) - #elif command == "vtext": - # _vlist = texgroup.pop(0) - # appendix = handle_tokens(_vlist, env.copy(), box=Vbox) - elif command in tex2uni: - uniindex = tex2uni[command] - appendix = handle_char(uniindex, env.copy()) - else: - #appendix = handle_tokens([r"\backslash"] + [ - #~ c for c in command], env.copy()) - #appendix.env = env.copy() - #print appendix - raise TexParseError("Unknown command: " + esc_char + command) - appendix = [appendix] - appendix.extend(texgroup) - #print "App",appendix - return appendix, env - -def handle_scripts(firsttype, texgroup, env): - sub = None - sup = None - env = env.copy() - # The environment for the script elements - _env = env.copy() - _env.scriptdepth += 1 - firstscript = texgroup.pop(0) - if firstscript in scripts: - # An "_" or "^", immediately folowed by another "_" or "^" - raise TexParseError("Missing { inserted. " + firsttype + firstscript) - elif is_command(firstscript): - command = firstscript.strip(esc_char) - texgroup, _env = handle_command(command, texgroup, _env) - firstscript = texgroup.pop(0) - else: - _tmp = handle_tokens([firstscript], _env) - firstscript = _tmp.items.pop(0) - if firsttype == "_": - sub = firstscript - else: - sup = firstscript - # Check if the next item is also a command for scripting - try: - second = texgroup[0] - except IndexError: - second = None - if second in scripts: - secondtype = texgroup.pop(0) - if secondtype == firsttype: - raise TexParseError("Double script: " + secondtype) - try: - secondscript = texgroup.pop(0) - except IndexError: - raise TexParseError("Empty script: " + secondtype) - if secondscript in scripts: - # An "_" or "^", immediately folowed by another "_" or "^" - raise TexParseError("Missing { inserted. "\ - + secondtype + secondscript) - elif is_command(secondscript): - command = secondscript.strip(esc_char) - texgroup, _env = handle_command(command, texgroup, _env) - secondscript = texgroup.pop(0) - else: - _tmp = handle_tokens([secondscript], _env) - secondscript = _tmp.items.pop(0) - if secondtype == "_": - sub = secondscript - else: - sup = secondscript - # Check if the next item is also a command for scripting - try: - next = texgroup[0] - except IndexError: - next = None - if next in scripts: - raise TexParseError("Double script: " + next) - return sub, sup, texgroup - -def handle_char(uniindex, env): - env = env.copy() - char = unichr(uniindex) - if not env.face: - env.face = infer_face(env, char) - return Char(env, char, uniindex=uniindex) - -def get_args(command, texgroup, env, num_args): - """Returns the arguments needed by a TeX command""" - args = [] - i = 0 - while i < num_args: - try: - arg = texgroup.pop(0) - except IndexError: - msg = "%s is missing it's %d argument"%(command, i+1) - raise TexParseError(msg) - # We skip space - if arg == " ": - continue - tmp = handle_tokens([arg], env.copy()) - arg = tmp.items.pop() - args.append(arg) - i += 1 - return texgroup, args - - -# Functions exported to backends -def math_parse_s_ft2font(s, dpi, fontsize, angle=0, output="AGG"): - """This function is called by the backends""" - # Reseting the variables used for rendering - for font in fonts.values(): - font.clear() - svg_elements.svg_glyphs = [] - svg_elements.svg_lines = [] - - s = s[1:-1] - parsed = parse_tex(_textclass(s)) - env = environment.copy() - env.dpi = dpi - env.fontsize = fontsize - env.output = output - parsed = handle_tokens(parsed, env) - #print "\n".join(str(parsed.__dict__).split(",")) - width, height = parsed.width + 2, parsed.height + 2 - #print width, height - if output == "AGG": - for key in fonts: - fonts[key].set_bitmap_size(width, height) - parsed.hrender(-parsed.items[0].hbearingx, height + parsed.ymin - 1) - #~ parsed.hrender(-parsed.hbearingx, height - 1 - ( - #~ parsed.height - parsed.hbearingy)) - if output == "AGG": - return width, height, fonts.values() - elif output == "SVG": - return width, height, svg_elements - -def math_parse_s_ft2font_svg(s, dpi, fontsize, angle=0): - return math_parse_s_ft2font(s, dpi, fontsize, angle, "SVG") - -def math_parse_s_ft2font1(s, dpi, fontsize, angle=0): - "Used only for testing" - s = s[1:-1] - parsed = parse_tex(_textclass(s)) - env = environment.copy() - env.dpi = dpi - env.fontsize = fontsize - parsed = handle_tokens(parsed, env) - #print "\n".join(str(parsed.__dict__).split(",")) - width, height = parsed.width + 10, parsed.height + 10 - width, height = 300, 300 - #print width, height - for key in fonts: - fonts[key].set_bitmap_size(width, height) - parsed.hrender(width/2., height/2.) - #fonts["mit"].draw_rect(0, 0, 40, 0) - #fonts["mit"].draw_rect(0, 1, 40, 0) - #parsed.hrender(20, 20) - #~ parsed.hrender(-parsed.hbearingx, height - 1 - ( - #~ parsed.height - parsed.hbearingy)) - _fonts = fonts.values() - return width, height, _fonts - - -if __name__ == '__main__': - pass - #texstring = r"\\{ \horse\ Hello\^ ^ a^b_c}" - #texstring = r" asdf { \horse{}tralala1234\ \zztop{} \ Hello\^^a^{b_c}}" - #texstring = r"{}{} { }" - #texstring = r"{{{_ }}}" - #texstring = r"\horse{}" - #texstring = r"\horse;,.?)_)(*(*^*%&$$%{} Haha! Kako je frajeru?" - #texstring = r"a_2\trav 32" - #texstring = r"a_24{\sum_4^5} _3" - #texstring = _textclass(r"1_2^{4^5}32 5") - #parsed = parse_tex(texstring) - #~ print bool(a) - #print is_scriptcommand('\\subscript') Modified: trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc =================================================================== --- trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc 2007-08-06 18:50:00 UTC (rev 3675) +++ trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc 2007-08-06 18:52:07 UTC (rev 3676) @@ -26,7 +26,7 @@ #### CONFIGURATION BEGINS HERE # the default backend; one of GTK GTKAgg GTKCairo FltkAgg QtAgg TkAgg # Agg Cairo GD GDK Paint PS PDF SVG Template -backend : TkAgg +backend : WXAgg numerix : numpy # numpy, Numeric or numarray #maskedarray : False # True to use external maskedarray module # instead of numpy.ma; this is a temporary @@ -150,6 +150,14 @@ #text.dvipnghack : False # some versions of dvipng don't handle # alpha channel properly. Use True to correct and flush # ~/.matplotlib/tex.cache before testing +#text.markup : 'plain' # Affects how text, such as titles and lables, are + # interpreted by default. + # 'plain': As plain, unformatted text + # 'tex': As TeX-like text. Text between $'s will be + # formatted as a TeX math expression. + # This setting has no effect when text.usetex is True. + # In that case, all text will be sent to TeX for + # processing. ### AXES # default face and edge color, default tick sizes, Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py =================================================================== --- trunk/matplotlib/lib/matplotlib/rcsetup.py 2007-08-06 18:50:00 UTC (rev 3675) +++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2007-08-06 18:52:07 UTC (rev 3676) @@ -458,16 +458,6 @@ 'svg.embed_char_paths' : [False, validate_bool], # True to save all characters as paths in the SVG 'plugins.directory' : ['.matplotlib_plugins', str], # where plugin directory is locate - # mathtext settings - 'mathtext.mathtext2' : [False, validate_bool], # Needed to enable Unicode - # fonts used by mathtext. These ship with matplotlib - 'mathtext.rm' : ['cmr10.ttf', str], # Roman (normal) - 'mathtext.it' : ['cmmi10.ttf', str], # Italic - 'mathtext.tt' : ['cmtt10.ttf', str], # Typewriter (monospaced) - 'mathtext.mit' : ['cmmi10.ttf', str], # Math italic - 'mathtext.cal' : ['cmsy10.ttf', str], # Caligraphic - 'mathtext.nonascii' : ['cmex10.ttf', str], # All other nonascii fonts - } if __name__ == '__main__': This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-06 20:53:37
|
Revision: 3677 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3677&view=rev Author: mdboom Date: 2007-08-06 13:53:11 -0700 (Mon, 06 Aug 2007) Log Message: ----------- Expose Unicode font functionality for mathtext through rcParams Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/_mathtext_data.py trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc trunk/matplotlib/lib/matplotlib/rcsetup.py trunk/matplotlib/matplotlibrc.template Modified: trunk/matplotlib/lib/matplotlib/_mathtext_data.py =================================================================== --- trunk/matplotlib/lib/matplotlib/_mathtext_data.py 2007-08-06 18:52:07 UTC (rev 3676) +++ trunk/matplotlib/lib/matplotlib/_mathtext_data.py 2007-08-06 20:53:11 UTC (rev 3677) @@ -2211,7 +2211,7 @@ '$': 36, '{': 123, '}': 125, -'imath': 0xfd, +'imath': 0x131, 'circumflexaccent' : 770, 'combiningbreve' : 774, 'combiningoverline' : 772, Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-06 18:52:07 UTC (rev 3676) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-06 20:53:11 UTC (rev 3677) @@ -133,7 +133,7 @@ from cStringIO import StringIO from math import floor, ceil from sets import Set -from unicodedata import category +import unicodedata from warnings import warn from numpy import inf, isinf @@ -462,7 +462,7 @@ cached_font = self.fonts.get(basename) if cached_font is None: - font = FT2Font(os.path.join(self.basepath, basename + ".ttf")) + font = FT2Font(basename) cached_font = self.CachedFont(font) self.fonts[basename] = cached_font self.fonts[font.postscript_name] = cached_font @@ -545,15 +545,24 @@ """ Use the Bakoma true type fonts for rendering """ - fontmap = { 'cal' : 'cmsy10', - 'rm' : 'cmr10', - 'tt' : 'cmtt10', - 'it' : 'cmmi10', - 'bf' : 'cmb10', - 'sf' : 'cmss10', - 'ex' : 'cmex10' - } - + _fontmap = { 'cal' : 'cmsy10', + 'rm' : 'cmr10', + 'tt' : 'cmtt10', + 'it' : 'cmmi10', + 'bf' : 'cmb10', + 'sf' : 'cmss10', + 'ex' : 'cmex10' + } + fontmap = {} + + def __init__(self, *args, **kwargs): + TruetypeFonts.__init__(self, *args, **kwargs) + if not len(self.fontmap): + for key, val in self._fontmap.items(): + fullpath = os.path.join(self.basepath, val + ".ttf") + self.fontmap[key] = fullpath + self.fontmap[val] = fullpath + def _get_offset(self, cached_font, glyph, fontsize, dpi): if cached_font.font.postscript_name == 'Cmex10': return glyph.height/64.0/2.0 + 256.0/64.0 * dpi/72.0 @@ -564,7 +573,7 @@ def _get_glyph(self, fontname, sym, fontsize): if fontname in self.fontmap and latex_to_bakoma.has_key(sym): basename, num = latex_to_bakoma[sym] - slanted = basename == "cmmi10" or sym in self._slanted_symbols + slanted = (basename == "cmmi10") or sym in self._slanted_symbols cached_font = self._get_font(basename) symbol_name = cached_font.font.get_glyph_name(num) num = cached_font.glyphmap[num] @@ -638,15 +647,24 @@ class UnicodeFonts(TruetypeFonts): """An abstract base class for handling Unicode fonts. """ - fontmap = { 'cal' : 'cmsy10', - 'rm' : 'DejaVuSerif', - 'tt' : 'DejaVuSansMono', - 'it' : 'DejaVuSerif-Italic', - 'bf' : 'DejaVuSerif-Bold', - 'sf' : 'DejaVuSans', - None : 'DejaVuSerif-Italic' - } + fontmap = {} + + def __init__(self, *args, **kwargs): + # This must come first so the backend's owner is set correctly + if rcParams['mathtext.fallback_to_cm']: + self.cm_fallback = BakomaFonts(*args, **kwargs) + else: + self.cm_fallback = None + TruetypeFonts.__init__(self, *args, **kwargs) + if not len(self.fontmap): + for texfont in "cal rm tt it bf sf".split(): + setting = rcParams['mathtext.' + texfont] + family, weight, style = setting + prop = FontProperties(family=family, weight=weight, style=style) + font = fontManager.findfont(prop) + self.fontmap[texfont] = font + def _get_offset(self, cached_font, glyph, fontsize, dpi): return 0. @@ -662,34 +680,66 @@ uniindex = get_unicode_index(sym[4:]) fontsize *= GROW_FACTOR else: - warn("No TeX to unicode mapping for '%s'" % sym, + uniindex = ord('?') + warn("No TeX to unicode mapping for '%s'" % sym.encode('ascii', 'replace'), MathTextWarning) # Only characters in the "Letter" class should be italicized in 'it' - # mode. This class includes greek letters, of course. - if (fontname == 'it' - and not category(unichr(uniindex)).startswith("L")): - fontname = 'rm' + # mode. Greek capital letters should be Roman. + if found_symbol: + new_fontname = fontname - slanted = (fontname == 'it') - - cached_font = self._get_font(fontname) - if found_symbol: + if fontname == 'it': + unistring = unichr(uniindex) + if (not unicodedata.category(unistring).startswith("L") + or unicodedata.name(unistring).startswith("GREEK CAPITAL")): + new_fontname = 'rm' + + slanted = (new_fontname == 'it') + cached_font = self._get_font(new_fontname) try: glyphindex = cached_font.charmap[uniindex] except KeyError: warn("Font '%s' does not have a glyph for '%s'" % - (cached_font.font.postscript_name, sym), + (cached_font.font.postscript_name, sym.encode('ascii', 'replace')), MathTextWarning) found_symbol = False if not found_symbol: - uniindex = 0xA4 # currency character, for lack of anything better - glyphindex = cached_font.charmap[uniindex] + if self.cm_fallback: + warn("Substituting with a symbol from the Computer Modern family.", + MathTextWarning) + return self.cm_fallback._get_glyph(fontname, sym, fontsize) + else: + new_fontname = fontname + cached_font = self._get_font(fontname) + uniindex = 0xA4 # currency character, for lack of anything better + glyphindex = cached_font.charmap[uniindex] + slanted = False symbol_name = cached_font.font.get_glyph_name(glyphindex) return cached_font, uniindex, symbol_name, fontsize, slanted + + def set_canvas_size(self, w, h): + 'Dimension the drawing canvas; may be a noop' + TruetypeFonts.set_canvas_size(self, w, h) + if self.cm_fallback: + self.cm_fallback.set_canvas_size(w, h) + def get_used_characters(self): + used_characters = dict(self.used_characters) + if self.cm_fallback: + fallback_characters = self.cm_fallback.get_used_characters() + for key, val in fallback_characters: + used_characters.setdefault(key, Set()).update(val) + return used_characters + + def get_fonts(self): + fonts = [x.font for x in self.fonts.values()] + if self.cm_fallback: + fonts.extend(self.cm_fallback.get_fonts()) + return list(set(fonts)) + class StandardPsFonts(Fonts): """ Use the standard postscript fonts for rendering to backend_ps @@ -750,7 +800,7 @@ # This class includes greek letters, so we're ok if (fontname == 'it' and (len(sym) > 1 or - not category(unicode(sym)).startswith("L"))): + not unicodedata.category(unicode(sym)).startswith("L"))): fontname = 'rm' found_symbol = False @@ -2302,10 +2352,10 @@ font_output = StandardPsFonts(prop) else: backend = self._backend_mapping[self.output]() - font_output = BakomaFonts(prop, backend) - # When we have a decent Unicode font, we should test and - # then make this available as an option - #~ font_output = UnicodeFonts(prop, backend) + if rcParams['mathtext.use_cm']: + font_output = BakomaFonts(prop, backend) + else: + font_output = UnicodeFonts(prop, backend) fontsize = prop.get_size_in_points() if self._parser is None: Modified: trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc =================================================================== --- trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc 2007-08-06 18:52:07 UTC (rev 3676) +++ trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc 2007-08-06 20:53:11 UTC (rev 3677) @@ -159,6 +159,22 @@ # In that case, all text will be sent to TeX for # processing. +# The following settings allow you to select the fonts in math mode. +# They map from a TeX font name to a 3-tuple of the form: +# (family, weight, style) +# These settings are only used if mathtext.use_cm is False, otherwise, the +# Bakoma TeX Computer Modern fonts are used. +#mathtext.cal : (['cursive'], 'normal', 'normal') +#mathtext.rm : (['serif'], 'normal', 'normal') +#mathtext.tt : (['monospace'], 'normal', 'normal') +#mathtext.it : (['serif'], 'normal', 'oblique') +#mathtext.bf : (['serif'], 'bold', 'normal') +#mathtext.sf : (['sans-serif'], 'normal', 'normal') +#mathtext.use_cm : True +#mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern + # fonts when a symbol can not be found in one of + # the user-specified math fonts. + ### AXES # default face and edge color, default tick sizes, # default fontsizes for ticklabels, and so on. See Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py =================================================================== --- trunk/matplotlib/lib/matplotlib/rcsetup.py 2007-08-06 18:52:07 UTC (rev 3676) +++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2007-08-06 20:53:11 UTC (rev 3677) @@ -198,6 +198,12 @@ except ValueError: raise ValueError('not a valid font size') +def validate_mathtext_font(s): + s = eval(s) + if type(s) in (list, tuple) and len(s) == 3: + return s + raise ValueError('Mathtext font specifier must be a 3-tuple of (family, weight, style)') + validate_markup = ValidateInStrings( 'markup', ['plain', 'tex'], @@ -357,6 +363,15 @@ 'text.fontsize' : ['medium', validate_fontsize], 'text.markup' : ['plain', validate_markup], + 'mathtext.cal' : [(['cursive'], 'normal', 'normal'), validate_mathtext_font], + 'mathtext.rm' : [(['serif'], 'normal', 'normal'), validate_mathtext_font], + 'mathtext.tt' : [(['monospace'], 'normal', 'normal'), validate_mathtext_font], + 'mathtext.it' : [(['serif'], 'normal', 'oblique'), validate_mathtext_font], + 'mathtext.bf' : [(['serif'], 'bold', 'normal'), validate_mathtext_font], + 'mathtext.sf' : [(['sans-serif'], 'normal', 'normal'), validate_mathtext_font], + 'mathtext.use_cm' : [True, validate_bool], + 'mathtext.fallback_to_cm' : [True, validate_bool], + 'image.aspect' : ['equal', validate_aspect], # equal, auto, a number 'image.interpolation' : ['bilinear', str], 'image.cmap' : ['jet', str], # one of gray, jet, etc Modified: trunk/matplotlib/matplotlibrc.template =================================================================== --- trunk/matplotlib/matplotlibrc.template 2007-08-06 18:52:07 UTC (rev 3676) +++ trunk/matplotlib/matplotlibrc.template 2007-08-06 20:53:11 UTC (rev 3677) @@ -159,6 +159,22 @@ # In that case, all text will be sent to TeX for # processing. +# The following settings allow you to select the fonts in math mode. +# They map from a TeX font name to a 3-tuple of the form: +# (family, weight, style) +# These settings are only used if mathtext.use_cm is False, otherwise, the +# Bakoma TeX Computer Modern fonts are used. +#mathtext.cal : (['cursive'], 'normal', 'normal') +#mathtext.rm : (['serif'], 'normal', 'normal') +#mathtext.tt : (['monospace'], 'normal', 'normal') +#mathtext.it : (['serif'], 'normal', 'oblique') +#mathtext.bf : (['serif'], 'bold', 'normal') +#mathtext.sf : (['sans-serif'], 'normal', 'normal') +#mathtext.use_cm : True +#mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern + # fonts when a symbol can not be found in one of + # the user-specified math fonts. + ### AXES # default face and edge color, default tick sizes, # default fontsizes for ticklabels, and so on. See This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-07 15:29:29
|
Revision: 3680 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3680&view=rev Author: mdboom Date: 2007-08-07 08:29:25 -0700 (Tue, 07 Aug 2007) Log Message: ----------- Improve font rendering considerably using a vertical hinting hack. Hinting is disabled for all of the "vector" backends, to correct spacing problems. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py trunk/matplotlib/lib/matplotlib/backends/backend_ps.py trunk/matplotlib/lib/matplotlib/backends/backend_svg.py trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/src/ft2font.cpp trunk/matplotlib/src/ft2font.h Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007-08-07 14:34:24 UTC (rev 3679) +++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007-08-07 15:29:25 UTC (rev 3680) @@ -82,7 +82,7 @@ from matplotlib.cbook import enumerate, is_string_like, exception_to_str from matplotlib.figure import Figure from matplotlib.font_manager import fontManager -from matplotlib.ft2font import FT2Font +from matplotlib.ft2font import FT2Font, LOAD_DEFAULT from matplotlib.mathtext import math_parse_s_ft2font from matplotlib.transforms import lbwh_to_bbox @@ -203,11 +203,10 @@ font = self._get_agg_font(prop) if font is None: return None - if len(s)==1 and ord(s)>127: - - font.load_char(ord(s)) + if len(s) == 1 and ord(s) > 127: + font.load_char(ord(s), flags=LOAD_DEFAULT) else: - font.set_text(s, angle) + font.set_text(s, angle, flags=LOAD_DEFAULT) font.draw_glyphs_to_bitmap() #print x, y, int(x), int(y) @@ -237,7 +236,7 @@ s, self.dpi.get(), prop) return width, height font = self._get_agg_font(prop) - font.set_text(s, 0.0) # the width and height of unrotated string + font.set_text(s, 0.0, flags=LOAD_DEFAULT) # the width and height of unrotated string w, h = font.get_width_height() w /= 64.0 # convert from subpixels h /= 64.0 Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-08-07 14:34:24 UTC (rev 3679) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-08-07 15:29:25 UTC (rev 3680) @@ -28,7 +28,7 @@ from matplotlib.font_manager import fontManager from matplotlib.afm import AFM from matplotlib.dviread import Dvi -from matplotlib.ft2font import FT2Font, FIXED_WIDTH, ITALIC, LOAD_NO_SCALE +from matplotlib.ft2font import FT2Font, FIXED_WIDTH, ITALIC, LOAD_NO_SCALE, LOAD_NO_HINTING from matplotlib.mathtext import math_parse_s_pdf from matplotlib.transforms import Bbox from matplotlib import ttconv @@ -517,7 +517,7 @@ def get_char_width(charcode): unicode = decode_char(charcode) - width = font.load_char(unicode, flags=LOAD_NO_SCALE).horiAdvance + width = font.load_char(unicode, flags=LOAD_NO_SCALE|LOAD_NO_HINTING).horiAdvance return cvt(width) firstchar, lastchar = 0, 255 @@ -1195,7 +1195,7 @@ else: font = self._get_font_ttf(prop) self.track_characters(font, s) - font.set_text(s, 0.0) + font.set_text(s, 0.0, flags=LOAD_NO_HINTING) y += font.get_descent() / 64.0 self.file.output(Op.begin_text, @@ -1222,7 +1222,7 @@ else: font = self._get_font_ttf(prop) - font.set_text(s, 0.0) + font.set_text(s, 0.0, flags=LOAD_NO_HINTING) w, h = font.get_width_height() w /= 64.0 h /= 64.0 Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2007-08-07 14:34:24 UTC (rev 3679) +++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2007-08-07 15:29:25 UTC (rev 3680) @@ -19,7 +19,7 @@ from matplotlib.figure import Figure from matplotlib.font_manager import fontManager -from matplotlib.ft2font import FT2Font, KERNING_UNFITTED, KERNING_DEFAULT, KERNING_UNSCALED +from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_NO_HINTING from matplotlib.ttconv import convert_ttf_to_ps from matplotlib.mathtext import math_parse_s_ps from matplotlib.text import Text @@ -292,7 +292,7 @@ return w, h font = self._get_font_ttf(prop) - font.set_text(s, 0.0) + font.set_text(s, 0.0, flags=LOAD_NO_HINTING) w, h = font.get_width_height() w /= 64.0 # convert from subpixels h /= 64.0 @@ -738,7 +738,7 @@ return self.draw_unicode(gc, x, y, s, prop, angle) else: font = self._get_font_ttf(prop) - font.set_text(s,0) + font.set_text(s, 0, flags=LOAD_NO_HINTING) self.track_characters(font, s) self.set_color(*gc.get_rgb()) @@ -782,10 +782,10 @@ gind = 0 else: name = font.get_glyph_name(gind) - glyph = font.load_char(ccode) + glyph = font.load_char(ccode, flags=LOAD_NO_HINTING) if lastgind is not None: - kern = font.get_kerning(lastgind, gind, KERNING_UNFITTED) + kern = font.get_kerning(lastgind, gind, KERNING_DEFAULT) else: kern = 0 lastgind = gind Modified: trunk/matplotlib/lib/matplotlib/backends/backend_svg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2007-08-07 14:34:24 UTC (rev 3679) +++ trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2007-08-07 15:29:25 UTC (rev 3680) @@ -8,7 +8,7 @@ from matplotlib.colors import rgb2hex from matplotlib.figure import Figure from matplotlib.font_manager import fontManager, FontProperties -from matplotlib.ft2font import FT2Font, KERNING_UNFITTED, KERNING_DEFAULT, KERNING_UNSCALED +from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_NO_HINTING from matplotlib.mathtext import math_parse_s_ft2font_svg from xml.sax.saxutils import escape as escape_xml_text @@ -266,10 +266,10 @@ if gind is None: ccode = ord('?') gind = 0 - glyph = font.load_char(ccode) + glyph = font.load_char(ccode, flags=LOAD_NO_HINTING) if lastgind is not None: - kern = font.get_kerning(lastgind, gind, KERNING_UNFITTED) + kern = font.get_kerning(lastgind, gind, KERNING_DEFAULT) else: kern = 0 lastgind = gind @@ -305,7 +305,7 @@ return char_id path_data = [] - glyph = font.load_char(ord(char)) + glyph = font.load_char(ord(char), flags=LOAD_NO_HINTING) currx, curry = 0.0, 0.0 for step in glyph.path: if step[0] == 0: # MOVE_TO @@ -431,7 +431,7 @@ math_parse_s_ft2font_svg(s, 72, prop) return width, height font = self._get_font(prop) - font.set_text(s, 0.0) + font.set_text(s, 0.0, flags=LOAD_NO_HINTING) w, h = font.get_width_height() w /= 64.0 # convert from subpixels h /= 64.0 Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-07 14:34:24 UTC (rev 3679) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-07 15:29:25 UTC (rev 3680) @@ -148,7 +148,7 @@ from matplotlib.afm import AFM from matplotlib.cbook import enumerate, iterable, Bunch, get_realpath_and_stat, \ is_string_like -from matplotlib.ft2font import FT2Font, KERNING_UNFITTED +from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_DEFAULT, LOAD_NO_HINTING from matplotlib.font_manager import fontManager, FontProperties from matplotlib._mathtext_data import latex_to_bakoma, \ latex_to_standard, tex2uni, type12uni, tex2type1, uni2type1 @@ -237,6 +237,9 @@ """Return a backend specific tuple of things to return to the backend after all processing is done.""" raise NotImplementedError() + + def get_hinting_type(self): + return LOAD_NO_HINTING class MathtextBackendAgg(MathtextBackend): def set_canvas_size(self, w, h): @@ -261,7 +264,10 @@ self.height, self.fonts_object.get_fonts(), self.fonts_object.get_used_characters()) - + + def get_hinting_type(self): + return LOAD_DEFAULT + class MathtextBackendPs(MathtextBackend): def __init__(self): self.pswriter = StringIO() @@ -487,7 +493,9 @@ font = cached_font.font font.set_size(fontsize, dpi) - glyph = font.load_char(num) + glyph = font.load_char( + num, + flags=self.mathtext_backend.get_hinting_type()) xmin, ymin, xmax, ymax = [val/64.0 for val in glyph.bbox] offset = self._get_offset(cached_font, glyph, fontsize, dpi) @@ -538,7 +546,7 @@ info1 = self._get_info(font1, sym1, fontsize1, dpi) info2 = self._get_info(font2, sym2, fontsize2, dpi) font = info1.font - return font.get_kerning(info1.num, info2.num, KERNING_UNFITTED) / 64.0 + return font.get_kerning(info1.num, info2.num, KERNING_DEFAULT) / 64.0 return 0.0 class BakomaFonts(TruetypeFonts): Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007-08-07 14:34:24 UTC (rev 3679) +++ trunk/matplotlib/src/ft2font.cpp 2007-08-07 15:29:25 UTC (rev 3680) @@ -5,6 +5,41 @@ #define FIXED_MAJOR(val) (*((short *) &val+1)) #define FIXED_MINOR(val) (*((short *) &val+0)) +/** + To improve the hinting of the fonts, this code uses a hack + presented here: + + http://antigrain.com/research/font_rasterization/index.html + + The idea is to limit the effect of hinting in the x-direction, while + preserving hinting in the y-direction. Since freetype does not + support this directly, the dpi in the x-direction is set higher than + in the y-direction, which affects the hinting grid. Then, a global + transform is placed on the font to shrink it back to the desired + size. While it is a bit surprising that the dpi setting affects + hinting, whereas the global transform does not, this is documented + behavior of freetype, and therefore hopefully unlikely to change. + The freetype 2 tutorial says: + + NOTE: The transformation is applied to every glyph that is + loaded through FT_Load_Glyph and is completely independent of + any hinting process. This means that you won't get the same + results if you load a glyph at the size of 24 pixels, or a glyph + at the size at 12 pixels scaled by 2 through a transform, + because the hints will have been computed differently (except + you have disabled hints). + + This hack is enabled only when VERTICAL_HINTING is defined, and will + only be effective when load_char and set_text are called with 'flags= + LOAD_DEFAULT', which is the default. + */ +#define VERTICAL_HINTING +#ifdef VERTICAL_HINTING +#define HORIZ_HINTING 8 +#else +#define HORIZ_HINTING 1 +#endif + FT_Library _ft2Library; FT2Image::FT2Image() : bRotated(false), buffer(NULL) {} @@ -17,12 +52,12 @@ FT_BBox bbox; FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_subpixels, &bbox ); - setattr("width", Py::Int( face->glyph->metrics.width) ); + setattr("width", Py::Int( face->glyph->metrics.width / HORIZ_HINTING) ); setattr("height", Py::Int( face->glyph->metrics.height) ); - setattr("horiBearingX", Py::Int( face->glyph->metrics.horiBearingX) ); + setattr("horiBearingX", Py::Int( face->glyph->metrics.horiBearingX / HORIZ_HINTING) ); setattr("horiBearingY", Py::Int( face->glyph->metrics.horiBearingY) ); - setattr("horiAdvance", Py::Int( face->glyph->metrics.horiAdvance) ); - setattr("linearHoriAdvance", Py::Int( face->glyph->linearHoriAdvance) ); + setattr("horiAdvance", Py::Int( face->glyph->metrics.horiAdvance / HORIZ_HINTING) ); + setattr("linearHoriAdvance", Py::Int( face->glyph->linearHoriAdvance / HORIZ_HINTING) ); setattr("vertBearingX", Py::Int( face->glyph->metrics.vertBearingX) ); setattr("vertBearingY", Py::Int( face->glyph->metrics.vertBearingY) ); @@ -341,7 +376,13 @@ } // set a default fontsize 12 pt at 72dpi +#ifdef VERTICAL_HINTING + error = FT_Set_Char_Size( face, 12 * 64, 0, 72 * HORIZ_HINTING, 72 ); + static FT_Matrix transform = { 65536 / HORIZ_HINTING, 0, 0, 65536 }; + FT_Set_Transform( face, &transform, 0 ); +#else error = FT_Set_Char_Size( face, 12 * 64, 0, 72, 72 ); +#endif //error = FT_Set_Char_Size( face, 20 * 64, 0, 80, 80 ); if (error) { std::ostringstream s; @@ -572,9 +613,17 @@ double ptsize = Py::Float(args[0]); double dpi = Py::Float(args[1]); +#ifdef VERTICAL_HINTING int error = FT_Set_Char_Size( face, (long)(ptsize * 64), 0, + (unsigned int)dpi * HORIZ_HINTING, + (unsigned int)dpi ); + static FT_Matrix transform = { 65536 / HORIZ_HINTING, 0, 0, 65536 }; + FT_Set_Transform( face, &transform, 0 ); +#else + int error = FT_Set_Char_Size( face, (long)(ptsize * 64), 0, (unsigned int)dpi, (unsigned int)dpi ); +#endif if (error) throw Py::RuntimeError("Could not set the fontsize"); return Py::Object(); @@ -648,7 +697,7 @@ FT_Vector delta; if (!FT_Get_Kerning( face, left, right, mode, &delta )) { - return Py::Int(delta.x); + return Py::Int(delta.x / HORIZ_HINTING); } else { return Py::Int(0); @@ -665,7 +714,7 @@ "You must call this before draw_glyphs_to_bitmap\n" "A sequence of x,y positions is returned"; Py::Object -FT2Font::set_text(const Py::Tuple & args) { +FT2Font::set_text(const Py::Tuple & args, const Py::Dict & kwargs) { _VERBOSE("FT2Font::set_text"); args.verify_length(2); @@ -687,6 +736,11 @@ angle = Py::Float(args[1]); angle = angle/360.0*2*3.14159; + + long flags = FT_LOAD_DEFAULT; + if (kwargs.hasKey("flags")) + flags = Py::Long(kwargs["flags"]); + //this computes width and height in subpixels so we have to divide by 64 matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L ); matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L ); @@ -721,9 +775,9 @@ FT_Vector delta; FT_Get_Kerning( face, previous, glyph_index, FT_KERNING_DEFAULT, &delta ); - pen.x += delta.x; + pen.x += delta.x / HORIZ_HINTING; } - error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT ); + error = FT_Load_Glyph( face, glyph_index, flags ); if ( error ) { std::cerr << "\tcould not load glyph for " << thischar << std::endl; continue; @@ -794,7 +848,7 @@ } char FT2Font::load_char__doc__[] = -"load_char(charcode, flags=LOAD_DEFAULT)\n" +"load_char(charcode, flags=LOAD_LOAD_DEFAULT)\n" "\n" "Load character with charcode in current fontfile and set glyph.\n" "The flags argument can be a bitwise-or of the LOAD_XXX constants.\n" @@ -881,22 +935,25 @@ FT_Int x, FT_Int y) { _VERBOSE("FT2Font::draw_bitmap"); - FT_Int i, j, p, q; - FT_Int width = (FT_Int)image.width; - FT_Int height = (FT_Int)image.height; + FT_Int image_width = (FT_Int)image.width; + FT_Int image_height = (FT_Int)image.height; + FT_Int char_width = bitmap->width; + FT_Int char_height = bitmap->rows; - FT_Int x1 = CLAMP(x, 0, width); - FT_Int y1 = CLAMP(y, 0, height); - FT_Int x2 = CLAMP(x + bitmap->width, 0, width); - FT_Int y2 = CLAMP(y + bitmap->rows, 0, height); + FT_Int x1 = CLAMP(x, 0, image_width); + FT_Int y1 = CLAMP(y, 0, image_height); + FT_Int x2 = CLAMP(x + char_width, 0, image_width); + FT_Int y2 = CLAMP(y + char_height, 0, image_height); - for ( i = x1, p = MAX(0, -x); i < x2; ++i, ++p ) - { - for ( j = y1, q = MAX(0, -y); j < y2; ++j, ++q ) - { - image.buffer[i + j*width] |= bitmap->buffer[p + q*bitmap->pitch]; - } - } + FT_Int x_start = MAX(0, -x); + FT_Int y_offset = y1 - MAX(0, -y); + + for ( FT_Int i = y1; i < y2; ++i ) { + unsigned char* dst = image.buffer + (i * image_width + x1); + unsigned char* src = bitmap->buffer + (((i - y_offset) * bitmap->pitch) + x_start); + for ( FT_Int j = x1; j < x2; ++j, ++dst, ++src ) + *dst |= *src; + } } char FT2Font::write_bitmap__doc__[] = @@ -1038,15 +1095,14 @@ FT_BBox string_bbox = compute_string_bbox(); - image.width = (string_bbox.xMax-string_bbox.xMin) / 64+2; - image.height = (string_bbox.yMax-string_bbox.yMin) / 64+2; + image.width = (string_bbox.xMax-string_bbox.xMin) / 64 + 2; + image.height = (string_bbox.yMax-string_bbox.yMin) / 64 + 2; - image.offsetx = (int)(string_bbox.xMin/64.0); + image.offsetx = (int)(string_bbox.xMin / 64.0); if (angle==0) image.offsety = -image.height; - else { + else image.offsety = (int)(-string_bbox.yMax/64.0); - } size_t numBytes = image.width*image.height; delete [] image.buffer; @@ -1054,8 +1110,6 @@ for (size_t n=0; n<numBytes; n++) image.buffer[n] = 0; - - for ( size_t n = 0; n < glyphs.size(); n++ ) { FT_BBox bbox; @@ -1074,11 +1128,8 @@ // now, draw to our target surface (convert position) //bitmap left and top in pixel, string bbox in subpixel - FT_Int x = (FT_Int)(bitmap->left-string_bbox.xMin/64.); - FT_Int y = (FT_Int)(string_bbox.yMax/64.-bitmap->top+1); - //make sure the index is non-neg - x = x<0?0:x; - y = y<0?0:y; + FT_Int x = (FT_Int)(bitmap->left - (string_bbox.xMin / 64.)); + FT_Int y = (FT_Int)((string_bbox.yMax / 64.) - bitmap->top + 1); draw_bitmap( &bitmap->bitmap, x, y); } @@ -1173,12 +1224,7 @@ FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[glyph->glyphInd]; - draw_bitmap( &bitmap->bitmap, - //x + bitmap->left, - x, - //y+bitmap->top - y - ); + draw_bitmap( &bitmap->bitmap, x, y); return Py::Object(); } @@ -1586,9 +1632,8 @@ behaviors().doc("Glyph"); behaviors().supportGetattr(); behaviors().supportSetattr(); +} - -} void FT2Font::init_type() { _VERBOSE("FT2Font::init_type"); @@ -1603,7 +1648,7 @@ FT2Font::load_char__doc__); add_varargs_method("draw_rect",&FT2Font::draw_rect, FT2Font::draw_rect__doc__); - add_varargs_method("draw_rect_filled",&FT2Font::draw_rect_filled, + add_varargs_method("draw_rect_filled",&FT2Font::draw_rect_filled, FT2Font::draw_rect_filled__doc__); add_varargs_method("draw_glyph_to_bitmap", &FT2Font::draw_glyph_to_bitmap, FT2Font::draw_glyph_to_bitmap__doc__); @@ -1620,7 +1665,7 @@ FT2Font::image_as_str__doc__); add_keyword_method("load_char", &FT2Font::load_char, FT2Font::load_char__doc__); - add_varargs_method("set_text", &FT2Font::set_text, + add_keyword_method("set_text", &FT2Font::set_text, FT2Font::set_text__doc__); add_varargs_method("set_size", &FT2Font::set_size, FT2Font::set_size__doc__); @@ -1766,6 +1811,5 @@ } ft2font_module::~ft2font_module() { - FT_Done_FreeType( _ft2Library ); } Modified: trunk/matplotlib/src/ft2font.h =================================================================== --- trunk/matplotlib/src/ft2font.h 2007-08-07 14:34:24 UTC (rev 3679) +++ trunk/matplotlib/src/ft2font.h 2007-08-07 15:29:25 UTC (rev 3680) @@ -56,7 +56,7 @@ Py::Object clear(const Py::Tuple & args); Py::Object set_size(const Py::Tuple & args); Py::Object set_charmap(const Py::Tuple & args); - Py::Object set_text(const Py::Tuple & args); + Py::Object set_text(const Py::Tuple & args, const Py::Dict & kwargs); Py::Object get_glyph(const Py::Tuple & args); Py::Object get_kerning(const Py::Tuple & args); Py::Object get_num_glyphs(const Py::Tuple & args); @@ -91,9 +91,10 @@ std::vector<FT_Vector> pos; std::vector<Glyph*> gms; double angle; + double ptsize; + double dpi; - FT_BBox compute_string_bbox(); void draw_bitmap( FT_Bitmap* bitmap, FT_Int x, FT_Int y); void set_scalable_attributes(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-08 17:41:31
|
Revision: 3687 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3687&view=rev Author: mdboom Date: 2007-08-08 10:41:30 -0700 (Wed, 08 Aug 2007) Log Message: ----------- Improve horizontal lines in mathtext in Agg backend. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/src/ft2font.cpp Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-08 16:52:44 UTC (rev 3686) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-08 17:41:30 UTC (rev 3687) @@ -254,10 +254,8 @@ def render_rect_filled(self, x1, y1, x2, y2): font = self.fonts_object.get_fonts()[0] font.draw_rect_filled( - floor(max(0, x1 - 1)), - floor(y1), - ceil(max(x2 - 1, x1)), - ceil(max(y2 - 1, y1))) + int(x1 + 0.5), int(y1 + 0.5) - 1, + int(x2 - 0.5), int(y2 - 0.5) - 1) def get_results(self): return (self.width, @@ -282,12 +280,12 @@ %(fontsize)s scalefont setfont %(ox)f %(oy)f moveto -/%(symbol_name)s glyphshow +/%(symbol_name)s glyphshow\n """ % locals() self.pswriter.write(ps) def render_rect_filled(self, x1, y1, x2, y2): - ps = "%f %f %f %f rectfill" % (x1, self.height - y2, x2 - x1, y2 - y1) + ps = "%f %f %f %f rectfill\n" % (x1, self.height - y2, x2 - x1, y2 - y1) self.pswriter.write(ps) def get_results(self): Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007-08-08 16:52:44 UTC (rev 3686) +++ trunk/matplotlib/src/ft2font.cpp 2007-08-08 17:41:30 UTC (rev 3687) @@ -1043,16 +1043,11 @@ FT_Int iwidth = (FT_Int)image.width; FT_Int iheight = (FT_Int)image.height; - if ( x0<0 || y0<0 || x1<0 || y1<0 || - x0>iwidth || x1>iwidth || - y0>iheight || y1>iheight ) - throw Py::ValueError("Rect coords outside image bounds"); + x0 = CLAMP(x0, 0, iwidth); + y0 = CLAMP(y0, 0, iheight); + x1 = CLAMP(x1, 0, iwidth); + y1 = CLAMP(y1, 0, iheight); - //~ for (long j=y0; j<y1; ++j) { - //~ for (long i=x0; i<x1+1; ++i) { - //~ image.buffer[i + j*iwidth] = 255; - //~ } - //~ } for (long j=y0; j<y1+1; j++) { for (long i=x0; i<x1+1; i++) { image.buffer[i + j*iwidth] = 255; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-09 15:14:30
|
Revision: 3694 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3694&view=rev Author: mdboom Date: 2007-08-09 08:14:28 -0700 (Thu, 09 Aug 2007) Log Message: ----------- Remove "deprecated conversion from string constant to char*" warnings. Modified Paths: -------------- trunk/matplotlib/src/_ttconv.cpp trunk/matplotlib/src/ft2font.cpp trunk/matplotlib/ttconv/pprdrv_tt.cpp trunk/matplotlib/ttconv/truetype.h Modified: trunk/matplotlib/src/_ttconv.cpp =================================================================== --- trunk/matplotlib/src/_ttconv.cpp 2007-08-09 15:13:50 UTC (rev 3693) +++ trunk/matplotlib/src/_ttconv.cpp 2007-08-09 15:14:28 UTC (rev 3694) @@ -39,7 +39,7 @@ virtual void write(const char* a) { if (_write_method) - if (! PyObject_CallFunction(_write_method, "s", a)) + if (! PyObject_CallFunction(_write_method, (char *)"s", a)) throw PythonExceptionOccurred(); } }; @@ -83,10 +83,12 @@ int fonttype; std::vector<int> glyph_ids; - static char *kwlist[] = { "filename", "output", "fonttype", "glyph_ids", NULL }; + static const char *kwlist[] = { + "filename", "output", "fonttype", "glyph_ids", NULL }; if (! PyArg_ParseTupleAndKeywords (args, kwds, - "sO&i|O&:convert_ttf_to_ps", kwlist, + "sO&i|O&:convert_ttf_to_ps", + (char**)kwlist, &filename, fileobject_to_PythonFileWriter, &output, @@ -140,10 +142,11 @@ std::vector<int> glyph_ids; PyObject* result; - static char *kwlist[] = { "filename", "glyph_ids", NULL }; + static const char *kwlist[] = { "filename", "glyph_ids", NULL }; if (! PyArg_ParseTupleAndKeywords (args, kwds, - "s|O&:convert_ttf_to_ps", kwlist, + "s|O&:convert_ttf_to_ps", + (char **)kwlist, &filename, pyiterable_to_vector_int, &glyph_ids)) Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007-08-09 15:13:50 UTC (rev 3693) +++ trunk/matplotlib/src/ft2font.cpp 2007-08-09 15:14:28 UTC (rev 3694) @@ -1411,8 +1411,8 @@ std::string tagname = Py::String(args[0]); int tag; - char *tags[] = {"head", "maxp", "OS/2", "hhea", - "vhea", "post", "pclt", NULL}; + const char *tags[] = {"head", "maxp", "OS/2", "hhea", + "vhea", "post", "pclt", NULL}; for (tag=0; tags[tag] != NULL; tag++) if (strcmp(tagname.c_str(), tags[tag]) == 0) Modified: trunk/matplotlib/ttconv/pprdrv_tt.cpp =================================================================== --- trunk/matplotlib/ttconv/pprdrv_tt.cpp 2007-08-09 15:13:50 UTC (rev 3693) +++ trunk/matplotlib/ttconv/pprdrv_tt.cpp 2007-08-09 15:14:28 UTC (rev 3694) @@ -107,7 +107,7 @@ ** is always 4 characters, though the last characters may be ** padding spaces. -----------------------------------------------------------------------*/ -BYTE *GetTable(struct TTFONT *font, char *name) +BYTE *GetTable(struct TTFONT *font, const char *name) { BYTE *ptr; ULONG x; @@ -181,10 +181,10 @@ /* Set default values to avoid future references to */ /* undefined pointers. */ font->PostName = font->FullName = - font->FamilyName = font->Version = font->Style = "unknown"; + font->FamilyName = font->Version = font->Style = (char*)"unknown"; font->Copyright = font->Trademark = (char*)NULL; - table_ptr = GetTable(font,"name"); /* pointer to table */ + table_ptr = GetTable(font, "name"); /* pointer to table */ try { numrecords = getUSHORT( table_ptr + 2 ); /* number of names */ strings = table_ptr + getUSHORT( table_ptr + 4 ); /* start of string storage */ @@ -654,10 +654,10 @@ */ void ttfont_sfnts(TTStreamWriter& stream, struct TTFONT *font) { - char *table_names[]= /* The names of all tables */ - { /* which it is worth while */ - "cvt ", /* to include in a Type 42 */ - "fpgm", /* PostScript font. */ + static const char *table_names[] = /* The names of all tables */ + { /* which it is worth while */ + "cvt ", /* to include in a Type 42 */ + "fpgm", /* PostScript font. */ "glyf", "head", "hhea", @@ -828,7 +828,7 @@ ** this array will instead convert PostScript character names ** to executable proceedures. --------------------------------------------------------------*/ -char *Apple_CharStrings[]={ +const char *Apple_CharStrings[]={ ".notdef",".null","nonmarkingreturn","space","exclam","quotedbl","numbersign", "dollar","percent","ampersand","quotesingle","parenleft","parenright", "asterisk","plus", "comma","hyphen","period","slash","zero","one","two", @@ -871,7 +871,7 @@ ** This routine is called by the one below. ** It is also called from pprdrv_tt2.c */ -char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex) +const char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex) { int GlyphIndex; static char temp[80]; @@ -1227,7 +1227,7 @@ i != glyph_ids.end(); ++i) { StringStreamWriter writer; tt_type3_charproc(writer, &font, *i); - char* name = ttfont_CharStrings_getname(&font, *i); + const char* name = ttfont_CharStrings_getname(&font, *i); dict.add_pair(name, writer.str().c_str()); } } Modified: trunk/matplotlib/ttconv/truetype.h =================================================================== --- trunk/matplotlib/ttconv/truetype.h 2007-08-09 15:13:50 UTC (rev 3693) +++ trunk/matplotlib/ttconv/truetype.h 2007-08-09 15:14:28 UTC (rev 3694) @@ -98,7 +98,7 @@ /* This is the one routine in pprdrv_tt.c that is */ /* called from pprdrv_tt.c. */ -char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex); +const char *ttfont_CharStrings_getname(struct TTFONT *font, int charindex); void tt_type3_charproc(TTStreamWriter& stream, struct TTFONT *font, int charindex); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ef...@us...> - 2007-08-12 07:21:50
|
Revision: 3701 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3701&view=rev Author: efiring Date: 2007-08-12 00:21:47 -0700 (Sun, 12 Aug 2007) Log Message: ----------- numpification of mlab Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/examples/axes_demo.py trunk/matplotlib/examples/colours.py trunk/matplotlib/examples/psd_demo.py trunk/matplotlib/examples/scatter_demo.py trunk/matplotlib/lib/matplotlib/art3d.py trunk/matplotlib/lib/matplotlib/mlab.py trunk/matplotlib/lib/matplotlib/pylab.py trunk/matplotlib/lib/matplotlib/ticker.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2007-08-12 06:08:36 UTC (rev 3700) +++ trunk/matplotlib/CHANGELOG 2007-08-12 07:21:47 UTC (rev 3701) @@ -1,24 +1,26 @@ +2007-08-11 Numpification and cleanup of mlab.py and some examples - EF + 2007-08-06 Removed mathtext2 -2007-07-31 Refactoring of distutils scripts. - - Will not fail on the entire build if an optional Python +2007-07-31 Refactoring of distutils scripts. + - Will not fail on the entire build if an optional Python package (e.g. Tkinter) is installed but its development headers are not (e.g. tk-devel). Instead, it will continue to build all other extensions. - - Provide an overview at the top of the output to display - what dependencies and their versions were found, and (by + - Provide an overview at the top of the output to display + what dependencies and their versions were found, and (by extension) what will be built. - Use pkg-config, when available, to find freetype2, since this was broken on Mac OS-X when using MacPorts in a non- standard location. 2007-07-30 Reorganized configuration code to work with traited config - objects. The new config system is located in the + objects. The new config system is located in the matplotlib.config package, but it is disabled by default. To enable it, set NEWCONFIG=True in matplotlib.__init__.py. - The new configuration system will still use the old + The new configuration system will still use the old matplotlibrc files by default. To switch to the experimental, - traited configuration, set USE_TRAITED_CONFIG=True in + traited configuration, set USE_TRAITED_CONFIG=True in config.__init__.py. 2007-07-29 Changed default pcolor shading to flat; added aliases Modified: trunk/matplotlib/examples/axes_demo.py =================================================================== --- trunk/matplotlib/examples/axes_demo.py 2007-08-12 06:08:36 UTC (rev 3700) +++ trunk/matplotlib/examples/axes_demo.py 2007-08-12 07:21:47 UTC (rev 3701) @@ -7,7 +7,7 @@ t = arange(0.0, 10.0, dt) r = exp(-t[:1000]/0.05) # impulse response x = randn(len(t)) -s = conv(x,r)[:len(x)]*dt # colored noise +s = convolve(x,r)[:len(x)]*dt # colored noise # the main axes is subplot(111) by default plot(t, s) Modified: trunk/matplotlib/examples/colours.py =================================================================== --- trunk/matplotlib/examples/colours.py 2007-08-12 06:08:36 UTC (rev 3700) +++ trunk/matplotlib/examples/colours.py 2007-08-12 07:21:47 UTC (rev 3701) @@ -2,14 +2,12 @@ """ Some simple functions to generate colours. """ -from matplotlib.numerix import asarray, asum -from matplotlib.mlab import linspace +import numpy as npy from matplotlib.colors import colorConverter -from matplotlib.numerix import sum def pastel(colour, weight=2.4): """ Convert colour into a nice pastel shade""" - rgb = asarray(colorConverter.to_rgb(colour)) + rgb = npy.asarray(colorConverter.to_rgb(colour)) # scale colour maxc = max(rgb) if maxc < 1.0 and maxc > 0: @@ -17,7 +15,7 @@ scale = 1.0 / maxc rgb = rgb * scale # now decrease saturation - total = asum(rgb) + total = rgb.sum() slack = 0 for x in rgb: slack += 1.0 - x @@ -33,7 +31,7 @@ def get_colours(n): """ Return n pastel colours. """ - base = asarray([[1,0,0], [0,1,0], [0,0,1]]) + base = npy.asarray([[1,0,0], [0,1,0], [0,0,1]]) if n <= 3: return base[0:n] @@ -44,7 +42,7 @@ colours = [] for start in (0, 1): - for x in linspace(0, 1, needed[start]+2): + for x in npy.linspace(0, 1, needed[start]+2): colours.append((base[start] * (1.0 - x)) + (base[start+1] * x)) Modified: trunk/matplotlib/examples/psd_demo.py =================================================================== --- trunk/matplotlib/examples/psd_demo.py 2007-08-12 06:08:36 UTC (rev 3700) +++ trunk/matplotlib/examples/psd_demo.py 2007-08-12 07:21:47 UTC (rev 3701) @@ -8,7 +8,7 @@ nse = randn(len(t)) r = exp(-t/0.05) -cnse = conv(nse, r)*dt +cnse = convolve(nse, r)*dt cnse = cnse[:len(t)] s = 0.1*sin(2*pi*t) + cnse Modified: trunk/matplotlib/examples/scatter_demo.py =================================================================== --- trunk/matplotlib/examples/scatter_demo.py 2007-08-12 06:08:36 UTC (rev 3700) +++ trunk/matplotlib/examples/scatter_demo.py 2007-08-12 07:21:47 UTC (rev 3701) @@ -6,6 +6,5 @@ y = 0.9*rand(N) area = pi*(10 * rand(N))**2 # 0 to 10 point radiuses scatter(x,y,s=area, marker='^', c='r') -savefig('scatter_demo') show() Modified: trunk/matplotlib/lib/matplotlib/art3d.py =================================================================== --- trunk/matplotlib/lib/matplotlib/art3d.py 2007-08-12 06:08:36 UTC (rev 3700) +++ trunk/matplotlib/lib/matplotlib/art3d.py 2007-08-12 07:21:47 UTC (rev 3701) @@ -327,7 +327,7 @@ source = image._A w,h,p = source.shape X,Y = meshgrid(arange(w),arange(h)) - Z = zeros((w,h)) + Z = npy.zeros((w,h)) tX,tY,tZ = proj3d.transform(X.flat,Y.flat,Z.flat,M) tX = reshape(tX,(w,h)) tY = reshape(tY,(w,h)) Modified: trunk/matplotlib/lib/matplotlib/mlab.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mlab.py 2007-08-12 06:08:36 UTC (rev 3700) +++ trunk/matplotlib/lib/matplotlib/mlab.py 2007-08-12 07:21:47 UTC (rev 3701) @@ -7,41 +7,41 @@ * cohere - Coherence (normalized cross spectral density) - * conv - convolution - - * corrcoef - The matrix of correlation coefficients - * csd - Cross spectral density uing Welch's average periodogram * detrend -- Remove the mean or best fit line from an array - * find - Return the indices where some condition is true + * find - Return the indices where some condition is true; + numpy.nonzero is similar but more general. - * linspace -- Linear spaced array from min to max - - * hist -- Histogram - * polyfit - least squares best polynomial fit of x to y * polyval - evaluate a vector for a vector of polynomial coeffs * prctile - find the percentiles of a sequence - * prepca - Principal Component's Analysis + * prepca - Principal Component Analysis * psd - Power spectral density uing Welch's average periodogram * rk4 - A 4th order runge kutta integrator for 1D or ND systems + + The following are deprecated; please import directly from numpy + (with care--function signatures may differ): + * conv - convolution (numpy.convolve) + * corrcoef - The matrix of correlation coefficients + * hist -- Histogram (numpy.histogram) + * linspace -- Linear spaced array from min to max + * meshgrid + * trapz - trapeziodal integration (trapz(x,y) -> numpy.trapz(y,x)) * vander - the Vandermonde matrix - * trapz - trapeziodal integration - Functions that don't exist in matlab(TM), but are useful anyway: * cohere_pairs - Coherence over all pairs. This is not a matlab function, but we compute coherence a lot in my lab, and we - compute it for alot of pairs. This function is optimized to do + compute it for a lot of pairs. This function is optimized to do this efficiently by caching the direct FFTs. Credits: @@ -55,63 +55,54 @@ """ from __future__ import division -import sys, random, datetime, csv +import sys, datetime, csv, warnings import numpy as npy -from numpy import linspace, meshgrid -from matplotlib import verbose +from matplotlib import nxutils +from matplotlib import cbook -import numerix -import numerix as nx -import numerix.mlab -from numerix import linear_algebra -import nxutils - -from numerix import array, asarray, arange, divide, exp, arctan2, \ - multiply, transpose, ravel, repeat, resize, reshape, floor, ceil,\ - absolute, matrixmultiply, power, take, where, Float, Int, asum,\ - dot, convolve, pi, Complex, ones, zeros, diagonal, Matrix, nonzero, \ - log, searchsorted, concatenate, sort, ArrayType, clip, size, indices,\ - conjugate, typecode, iscontiguous - - -from numerix.mlab import hanning, cov, diff, svd, rand, std -from numerix.fft import fft, inverse_fft - -from cbook import iterable, is_string_like, to_filehandle, reversed - +# set is a new builtin function in 2.4; delete the following when +# support for 2.3 is dropped. try: set except NameError: from sets import Set as set +def linspace(*args, **kw): + warnings.warn("use numpy.linspace", DeprecationWarning) + return npy.linspace(*args, **kw) +def meshgrid(x,y): + warnings.warn("use numpy.meshgrid", DeprecationWarning) + return npy.meshgrid(x,y) + def mean(x, dim=None): - if len(x)==0: return None - elif dim is None: - return numerix.mlab.mean(x) - else: return numerix.mlab.mean(x, dim) + warnings.warn("Use numpy.mean(x) or x.mean()", DeprecationWarning) + if len(x)==0: return None + return npy.mean(x, axis=dim) def logspace(xmin,xmax,N): - return exp(linspace(log(xmin), log(xmax),Nh)) + return npy.exp(npy.linspace(npy.log(xmin), npy.log(xmax), N)) def _norm(x): "return sqrt(x dot x)" - return numerix.mlab.sqrt(dot(x,x)) + return npy.sqrt(npy.dot(x,x)) def window_hanning(x): "return x times the hanning window of len(x)" - return hanning(len(x))*x + return npy.hanning(len(x))*x def window_none(x): "No window function; simply return x" return x +#from numpy import convolve as conv def conv(x, y, mode=2): 'convolve x with y' - return convolve(x,y,mode) + warnings.warn("Use numpy.convolve(x, y, mode='full')", DeprecationWarning) + return npy.convolve(x,y,mode) def detrend(x, key=None): if key is None or key=='constant': @@ -119,27 +110,34 @@ elif key=='linear': return detrend_linear(x) +def demean(x, axis=0): + "Return x minus its mean along the specified axis" + x = npy.asarray(x) + if axis: + ind = [slice(None)] * axis + ind.append(npy.newaxis) + return x - x.mean(axis)[ind] + return x - x.mean(axis) + def detrend_mean(x): "Return x minus the mean(x)" - return x - mean(x) + return x - x.mean() def detrend_none(x): "Return x: no detrending" return x -def detrend_linear(x): - "Return x minus best fit line; 'linear' detrending " - - # I'm going to regress x on xx=range(len(x)) and return x - - # (b*xx+a). Now that I have polyfit working, I could convert the - # code here, but if it ain't broke, don't fix it! - xx = arange(float(len(x))) - X = transpose(array([xx]+[x])) - C = cov(X) +def detrend_linear(y): + "Return y minus best fit line; 'linear' detrending " + # This is faster than an algorithm based on linalg.lstsq. + x = npy.arange(len(y), dtype=npy.float_) + C = npy.cov(x, y, bias=1) b = C[0,1]/C[0,0] - a = mean(x) - b*mean(xx) - return x-(b*xx+a) + a = y.mean() - b*x.mean() + return y - (b*x + a) + + def psd(x, NFFT=256, Fs=2, detrend=detrend_none, window=window_hanning, noverlap=0): """ @@ -148,10 +146,13 @@ is detrended by function detrend and windowed by function window. noperlap gives the length of the overlap between segments. The absolute(fft(segment))**2 of each segment are averaged to compute Pxx, - with a scaling to correct for power loss due to windowing. Fs is - the sampling frequency. + with a scaling to correct for power loss due to windowing. - -- NFFT must be a power of 2 + Fs is the sampling frequency (samples per time unit). It is used + to calculate the Fourier frequencies, freqs, in cycles per time + unit. + + -- NFFT must be even; a power 2 is most efficient. -- detrend is a functions, unlike in matlab where it is a vector. -- window can be a function or a vector of length NFFT. To create window vectors see numpy.blackman, numpy.hamming, numpy.bartlett, @@ -166,46 +167,45 @@ Procedures, John Wiley & Sons (1986) """ - + # I think we could remove this condition without hurting anything. if NFFT % 2: - raise ValueError, 'NFFT must be a power of 2' + raise ValueError('NFFT must be even') - x = asarray(x) # make sure we're dealing with a numpy array + x = npy.asarray(x) # make sure we're dealing with a numpy array # zero pad x up to NFFT if it is shorter than NFFT if len(x)<NFFT: n = len(x) - x = resize(x, (NFFT,)) + x = npy.resize(x, (NFFT,)) # Can't use resize method. x[n:] = 0 - # for real x, ignore the negative frequencies if npy.iscomplexobj(x): numFreqs = NFFT else: numFreqs = NFFT//2+1 - if iterable(window): - assert(len(window) == NFFT) - windowVals = window + if cbook.iterable(window): + assert(len(window) == NFFT) + windowVals = window else: - windowVals = window(ones((NFFT,),typecode(x))) + windowVals = window(npy.ones((NFFT,),x.dtype)) step = NFFT-noverlap ind = range(0,len(x)-NFFT+1,step) n = len(ind) - Pxx = zeros((numFreqs,n), float) + Pxx = npy.zeros((numFreqs,n), npy.float_) # do the ffts of the slices for i in range(n): thisX = x[ind[i]:ind[i]+NFFT] - thisX = windowVals*detrend(thisX) - fx = absolute(fft(thisX))**2 - Pxx[:,i] = divide(fx[:numFreqs], norm(windowVals)**2) + thisX = windowVals * detrend(thisX) + fx = npy.absolute(npy.fft.fft(thisX))**2 + Pxx[:,i] = fx[:numFreqs] + if n>1: + Pxx = Pxx.mean(axis=1) # Scale the spectrum by the norm of the window to compensate for # windowing loss; see Bendat & Piersol Sec 11.5.2 - if n>1: - Pxx = mean(Pxx,1) + Pxx /= (npy.abs(windowVals)**2).sum() - freqs = Fs/NFFT*arange(numFreqs) - Pxx.shape = len(freqs), + freqs = Fs/NFFT * npy.arange(numFreqs) return Pxx, freqs @@ -221,7 +221,7 @@ correct for power loss due to windowing. Fs is the sampling frequency. - NFFT must be a power of 2 + NFFT must be even; a power of 2 is most efficient window can be a function or a vector of length NFFT. To create window vectors see numpy.blackman, numpy.hamming, numpy.bartlett, @@ -229,8 +229,6 @@ Returns the tuple Pxy, freqs - - Refs: Bendat & Piersol -- Random Data: Analysis and Measurement Procedures, John Wiley & Sons (1986) @@ -238,34 +236,34 @@ """ if NFFT % 2: - raise ValueError, 'NFFT must be a power of 2' + raise ValueError, 'NFFT must be even' - x = asarray(x) # make sure we're dealing with a numpy array - y = asarray(y) # make sure we're dealing with a numpy array + x = npy.asarray(x) # make sure we're dealing with a numpy array + y = npy.asarray(y) # make sure we're dealing with a numpy array # zero pad x and y up to NFFT if they are shorter than NFFT if len(x)<NFFT: n = len(x) - x = resize(x, (NFFT,)) + x = npy.resize(x, (NFFT,)) x[n:] = 0 if len(y)<NFFT: n = len(y) - y = resize(y, (NFFT,)) + y = npy.resize(y, (NFFT,)) y[n:] = 0 # for real x, ignore the negative frequencies if npy.iscomplexobj(x): numFreqs = NFFT else: numFreqs = NFFT//2+1 - if iterable(window): - assert(len(window) == NFFT) - windowVals = window + if cbook.iterable(window): + assert(len(window) == NFFT) + windowVals = window else: - windowVals = window(ones((NFFT,),typecode(x))) + windowVals = window(npy.ones((NFFT,), x.dtype)) step = NFFT-noverlap ind = range(0,len(x)-NFFT+1,step) n = len(ind) - Pxy = zeros((numFreqs,n), complex) + Pxy = npy.zeros((numFreqs,n), npy.complex_) # do the ffts of the slices for i in range(n): @@ -273,24 +271,107 @@ thisX = windowVals*detrend(thisX) thisY = y[ind[i]:ind[i]+NFFT] thisY = windowVals*detrend(thisY) - fx = fft(thisX) - fy = fft(thisY) - Pxy[:,i] = conjugate(fx[:numFreqs])*fy[:numFreqs] + fx = npy.fft.fft(thisX) + fy = npy.fft.fft(thisY) + Pxy[:,i] = npy.conjugate(fx[:numFreqs])*fy[:numFreqs] # Scale the spectrum by the norm of the window to compensate for # windowing loss; see Bendat & Piersol Sec 11.5.2 - if n>1: Pxy = mean(Pxy,1) - Pxy = divide(Pxy, norm(windowVals)**2) - freqs = Fs/NFFT*arange(numFreqs) - Pxy.shape = len(freqs), + if n>1: + Pxy = Pxy.mean(axis=1) + Pxy /= (npy.abs(windowVals)**2).sum() + freqs = Fs/NFFT*npy.arange(numFreqs) return Pxy, freqs +def specgram(x, NFFT=256, Fs=2, detrend=detrend_none, + window=window_hanning, noverlap=128): + """ + Compute a spectrogram of data in x. Data are split into NFFT + length segements and the PSD of each section is computed. The + windowing function window is applied to each segment, and the + amount of overlap of each segment is specified with noverlap. + + window can be a function or a vector of length NFFT. To create + window vectors see numpy.blackman, numpy.hamming, numpy.bartlett, + scipy.signal, scipy.signal.get_window etc. + + See psd for more info. (psd differs in the default overlap; + in returning the mean of the segment periodograms; and in not + returning times.) + + If x is real (i.e. non-Complex) only the positive spectrum is + given. If x is Complex then the complete spectrum is given. + + returns: + Pxx - 2-D array, columns are the periodograms of + successive segments + freqs - 1-D array of frequencies corresponding to + the rows in Pxx + t - 1-D array of times corresponding to midpoints of + segments. + + """ + x = npy.asarray(x) + assert(NFFT>noverlap) + #if npy.log(NFFT)/npy.log(2) != int(npy.log(NFFT)/npy.log(2)): + # raise ValueError, 'NFFT must be a power of 2' + if NFFT % 2: + raise ValueError('NFFT must be even') + + + # zero pad x up to NFFT if it is shorter than NFFT + if len(x)<NFFT: + n = len(x) + x = resize(x, (NFFT,)) + x[n:] = 0 + + + # for real x, ignore the negative frequencies + if npy.iscomplexobj(x): + numFreqs=NFFT + else: + numFreqs = NFFT//2+1 + + if cbook.iterable(window): + assert(len(window) == NFFT) + windowVals = npy.asarray(window) + else: + windowVals = window(npy.ones((NFFT,),x.dtype)) + step = NFFT-noverlap + ind = npy.arange(0,len(x)-NFFT+1,step) + n = len(ind) + Pxx = npy.zeros((numFreqs,n), npy.float_) + # do the ffts of the slices + + for i in range(n): + thisX = x[ind[i]:ind[i]+NFFT] + thisX = windowVals*detrend(thisX) + fx = npy.absolute(npy.fft.fft(thisX))**2 + Pxx[:,i] = fx[:numFreqs] + # Scale the spectrum by the norm of the window to compensate for + # windowing loss; see Bendat & Piersol Sec 11.5.2 + Pxx /= (npy.abs(windowVals)**2).sum() + t = 1/Fs*(ind+NFFT/2) + freqs = Fs/NFFT*npy.arange(numFreqs) + + if npy.iscomplexobj(x): + # center the frequency range at zero + freqs = npy.concatenate((freqs[NFFT/2:]-Fs,freqs[:NFFT/2])) + Pxx = npy.concatenate((Pxx[NFFT/2:,:],Pxx[:NFFT/2,:]),0) + + return Pxx, freqs, t + + + +_coh_error = """Coherence is calculated by averaging over NFFT +length segments. Your signal is too short for your choice of NFFT. +""" def cohere(x, y, NFFT=256, Fs=2, detrend=detrend_none, window=window_hanning, noverlap=0): """ - cohere the coherence between x and y. Coherence is the normalized + The coherence between x and y. Coherence is the normalized cross spectral density Cxy = |Pxy|^2/(Pxx*Pyy) @@ -305,59 +386,33 @@ """ if len(x)<2*NFFT: - raise RuntimeError('Coherence is calculated by averaging over NFFT length segments. Your signal is too short for your choice of NFFT') + raise ValueError(_coh_error) Pxx, f = psd(x, NFFT, Fs, detrend, window, noverlap) Pyy, f = psd(y, NFFT, Fs, detrend, window, noverlap) Pxy, f = csd(x, y, NFFT, Fs, detrend, window, noverlap) - Cxy = divide(absolute(Pxy)**2, Pxx*Pyy) - Cxy.shape = len(f), + Cxy = npy.divide(npy.absolute(Pxy)**2, Pxx*Pyy) + Cxy.shape = (len(f),) return Cxy, f def corrcoef(*args): """ corrcoef(X) where X is a matrix returns a matrix of correlation - coefficients for each numrows observations and numcols variables. + coefficients for the columns of X. - corrcoef(x,y) where x and y are vectors returns the matrix or + corrcoef(x,y) where x and y are vectors returns the matrix of correlation coefficients for x and y. - Numeric arrays can be real or complex + Numpy arrays can be real or complex The correlation matrix is defined from the covariance matrix C as r(i,j) = C[i,j] / sqrt(C[i,i]*C[j,j]) """ + warnings.warn("Use numpy.corrcoef", DeprecationWarning) + kw = dict(rowvar=False) + return npy.corrcoef(*args, **kw) - - if len(args)==2: - X = transpose(array([args[0]]+[args[1]])) - elif len(args)==1: - X = asarray(args[0]) - else: - raise RuntimeError, 'Only expecting 1 or 2 arguments' - - - C = cov(X) - - if len(args)==2: - d = resize(diagonal(C), (2,1)) - denom = numerix.mlab.sqrt(matrixmultiply(d,transpose(d))) - else: - dc = diagonal(C) - N = len(dc) - shape = N,N - vi = resize(dc, shape) - denom = numerix.mlab.sqrt(vi*transpose(vi)) # element wise multiplication - - - r = divide(C,denom) - try: return r.real - except AttributeError: return r - - - - def polyfit(x,y,N): """ @@ -385,6 +440,8 @@ p = (XT*X)^-1 * XT * y where XT is the transpose of X and -1 denotes the inverse. + Numerically, however, this is not a good method, so we use + numpy.linalg.lstsq. For more info, see http://mathworld.wolfram.com/LeastSquaresFittingPolynomial.html, @@ -394,19 +451,20 @@ See also polyval """ + x = npy.asarray(x, dtype=npy.float_) + #y = npy.asarray(y, dtype=npy.float_) + #y.shape = (len(y),1) + #X = npy.matrix(npy.vander(x, N+1)) + #Xt = npy.matrix(X.transpose()) + #c = npy.array(npy.linalg.inv(Xt*X)*Xt*y) # convert back to array + #c.shape = (N+1,) + #return c + X = npy.vander(x, N+1) + return npy.linalg.lstsq(X, y)[0] - x = asarray(x)+0. - y = asarray(y)+0. - y = reshape(y, (len(y),1)) - X = Matrix(vander(x, N+1)) - Xt = Matrix(transpose(X)) - c = array(linear_algebra.inverse(Xt*X)*Xt*y) # convert back to array - c.shape = (N+1,) - return c - def polyval(p,x): """ y = polyval(p,x) @@ -423,11 +481,11 @@ See also polyfit """ - x = asarray(x)+0. - p = reshape(p, (len(p),1)) - X = vander(x,len(p)) - y = matrixmultiply(X,p) - return reshape(y, x.shape) + x = npy.asarray(x, dtype=npy.float_) + p = npy.asarray(p, dtype=npy.float_).reshape((len(p),1)) + X = npy.vander(x,len(p)) + y = npy.dot(X,p) + return y.reshape(x.shape) def vander(x,N=None): @@ -439,14 +497,10 @@ None it defaults to len(x). """ - if N is None: N=len(x) - X = ones( (len(x),N), typecode(x)) - for i in range(N-1): - X[:,i] = x**(N-i-1) - return X + warnings.warn("Use numpy.vander()", DeprecationWarning) + return npy.vander(x, N) - def donothing_callback(*args): pass @@ -523,7 +577,7 @@ # zero pad if X is too short if numRows < NFFT: tmp = X - X = zeros( (NFFT, numCols), typecode(X)) + X = npy.zeros( (NFFT, numCols), X.dtype) X[:numRows,:] = tmp del tmp @@ -544,11 +598,11 @@ # cache the FFT of every windowed, detrended NFFT length segement # of every channel. If preferSpeedOverMemory, cache the conjugate # as well - if iterable(window): - assert(len(window) == NFFT) - windowVals = window + if cbook.iterable(window): + assert(len(window) == NFFT) + windowVals = window else: - windowVals = window(ones((NFFT,), typecode(X))) + windowVals = window(npy.ones((NFFT,), typecode(X))) ind = range(0, numRows-NFFT+1, NFFT-noverlap) numSlices = len(ind) FFTSlices = {} @@ -558,7 +612,7 @@ normVal = norm(windowVals)**2 for iCol in allColumns: progressCallback(i/Ncols, 'Cacheing FFTs') - Slices = zeros( (numSlices,numFreqs), complex) + Slices = npy.zeros( (numSlices,numFreqs), dtype=npy.complex_) for iSlice in slices: thisSlice = X[ind[iSlice]:ind[iSlice]+NFFT, iCol] thisSlice = windowVals*detrend(thisSlice) @@ -567,7 +621,7 @@ FFTSlices[iCol] = Slices if preferSpeedOverMemory: FFTConjSlices[iCol] = conjugate(Slices) - Pxx[iCol] = divide(mean(absolute(Slices)**2), normVal) + Pxx[iCol] = npy.divide(npy.mean(absolute(Slices)**2), normVal) del Slices, ind, windowVals # compute the coherences and phases for all pairs using the @@ -584,47 +638,45 @@ if preferSpeedOverMemory: Pxy = FFTSlices[i] * FFTConjSlices[j] else: - Pxy = FFTSlices[i] * conjugate(FFTSlices[j]) - if numSlices>1: Pxy = mean(Pxy) - Pxy = divide(Pxy, normVal) - Cxy[(i,j)] = divide(absolute(Pxy)**2, Pxx[i]*Pxx[j]) - Phase[(i,j)] = arctan2(Pxy.imag, Pxy.real) + Pxy = FFTSlices[i] * npy.conjugate(FFTSlices[j]) + if numSlices>1: Pxy = npy.mean(Pxy) + Pxy = npy.divide(Pxy, normVal) + Cxy[(i,j)] = npy.divide(npy.absolute(Pxy)**2, Pxx[i]*Pxx[j]) + Phase[(i,j)] = npy.arctan2(Pxy.imag, Pxy.real) - freqs = Fs/NFFT*arange(numFreqs) + freqs = Fs/NFFT*npy.arange(numFreqs) if returnPxx: - return Cxy, Phase, freqs, Pxx + return Cxy, Phase, freqs, Pxx else: - return Cxy, Phase, freqs + return Cxy, Phase, freqs def entropy(y, bins): - """ - Return the entropy of the data in y + """ + Return the entropy of the data in y - \sum p_i log2(p_i) where p_i is the probability of observing y in - the ith bin of bins. bins can be a number of bins or a range of - bins; see hist + \sum p_i log2(p_i) where p_i is the probability of observing y in + the ith bin of bins. bins can be a number of bins or a range of + bins; see numpy.histogram - Compare S with analytic calculation for a Gaussian - x = mu + sigma*randn(200000) - Sanalytic = 0.5 * ( 1.0 + log(2*pi*sigma**2.0) ) + Compare S with analytic calculation for a Gaussian + x = mu + sigma*randn(200000) + Sanalytic = 0.5 * ( 1.0 + log(2*pi*sigma**2.0) ) - """ + """ + n,bins = npy.histogram(y, bins) + n = n.astype(npy.float_) + n = npy.take(n, npy.nonzero(n)[0]) # get the positive - n,bins = hist(y, bins) - n = n.astype(float) + p = npy.divide(n, len(y)) - n = npy.take(n, npy.nonzero(n)[0]) # get the positive + delta = bins[1]-bins[0] + S = -1.0*npy.sum(p*log(p)) + log(delta) + #S = -1.0*npy.sum(p*log(p)) + return S - p = divide(n, len(y)) - - delta = bins[1]-bins[0] - S = -1.0*asum(p*log(p)) + log(delta) - #S = -1.0*asum(p*log(p)) - return S - def hist(y, bins=10, normed=0): """ Return the histogram of y with bins equally sized bins. If bins @@ -638,226 +690,174 @@ If y has rank>1, it will be raveled. If y is masked, only the unmasked values will be used. Credits: the Numeric 22 documentation - - - """ - if hasattr(y, 'compressed'): - y = y.compressed() - else: - y = asarray(y) - if len(y.shape)>1: y = ravel(y) + warnings.warn("Use numpy.histogram()", DeprecationWarning) + return npy.histogram(y, bins=bins, range=None, normed=normed) - if not iterable(bins): - ymin, ymax = min(y), max(y) - if ymin==ymax: - ymin -= 0.5 - ymax += 0.5 - - if bins==1: bins=ymax - dy = (ymax-ymin)/bins - bins = ymin + dy*arange(bins) - - - n = searchsorted(sort(y), bins) - n = diff(concatenate([n, [len(y)]])) - if normed: - db = bins[1]-bins[0] - return 1/(len(y)*db)*n, bins - else: - return n, bins - - def normpdf(x, *args): - "Return the normal pdf evaluated at x; args provides mu, sigma" - mu, sigma = args - return 1/(numerix.mlab.sqrt(2*pi)*sigma)*exp(-0.5 * (1/sigma*(x - mu))**2) + "Return the normal pdf evaluated at x; args provides mu, sigma" + mu, sigma = args + return 1/(npy.sqrt(2*npy.pi)*sigma)*npy.exp(-0.5 * (1/sigma*(x - mu))**2) def levypdf(x, gamma, alpha): - "Returm the levy pdf evaluated at x for params gamma, alpha" + "Returm the levy pdf evaluated at x for params gamma, alpha" - N = len(x) + N = len(x) - if N%2 != 0: - raise ValueError, 'x must be an event length array; try\n' + \ - 'x = linspace(minx, maxx, N), where N is even' + if N%2 != 0: + raise ValueError, 'x must be an event length array; try\n' + \ + 'x = npy.linspace(minx, maxx, N), where N is even' - dx = x[1]-x[0] + dx = x[1]-x[0] - f = 1/(N*dx)*arange(-N/2, N/2, float) + f = 1/(N*dx)*npy.arange(-N/2, N/2, npy.float_) - ind = concatenate([arange(N/2, N, int), - arange(0, N/2, int)]) - df = f[1]-f[0] - cfl = exp(-gamma*absolute(2*pi*f)**alpha) + ind = npy.concatenate([npy.arange(N/2, N, int), + npy.arange(0, N/2, int)]) + df = f[1]-f[0] + cfl = exp(-gamma*npy.absolute(2*pi*f)**alpha) - px = fft(take(cfl,ind)*df).astype(float) - return take(px, ind) + px = npy.fft.fft(npy.take(cfl,ind)*df).astype(npy.float_) + return npy.take(px, ind) - - - - def find(condition): - "Return the indices where condition is true" - res, = npy.nonzero(condition) - return res + "Return the indices where ravel(condition) is true" + res, = npy.nonzero(npy.ravel(condition)) + return res - - def trapz(x, y): - if len(x)!=len(y): - raise ValueError, 'x and y must have the same length' - if len(x)<2: - raise ValueError, 'x and y must have > 1 element' - return asum(0.5*diff(x)*(y[1:]+y[:-1])) - - - -def longest_contiguous_ones(x): """ - return the indicies of the longest stretch of contiguous ones in x, - assuming x is a vector of zeros and ones. + Trapezoidal integral of y(x). """ - if len(x)==0: return array([]) + warnings.warn("Use numpy.trapz(y,x) instead of trapz(x,y)", DeprecationWarning) + return npy.trapz(y, x) + #if len(x)!=len(y): + # raise ValueError, 'x and y must have the same length' + #if len(x)<2: + # raise ValueError, 'x and y must have > 1 element' + #return npy.sum(0.5*npy.diff(x)*(y[1:]+y[:-1])) - ind = find(x==0) - if len(ind)==0: return arange(len(x)) - if len(ind)==len(x): return array([]) - y = zeros( (len(x)+2,), typecode(x)) - y[1:-1] = x - dif = diff(y) - up = find(dif == 1); - dn = find(dif == -1); - ind = find( dn-up == max(dn - up)) - ind = arange(take(up, ind), take(dn, ind)) - return ind - - -def longest_ones(x): +def longest_contiguous_ones(x): """ - return the indicies of the longest stretch of contiguous ones in x, + return the indices of the longest stretch of contiguous ones in x, assuming x is a vector of zeros and ones. - If there are two equally long stretches, pick the first + """ - x = asarray(x) - if len(x)==0: return array([]) + x = npy.ravel(x) + if len(x)==0: + return npy.array([]) - #print 'x', x - ind = find(x==0) - if len(ind)==0: return arange(len(x)) - if len(ind)==len(x): return array([]) + ind = (x==0).nonzero()[0] + if len(ind)==0: + return npy.arange(len(x)) + if len(ind)==len(x): + return npy.array([]) - y = zeros( (len(x)+2,), int) + y = npy.zeros( (len(x)+2,), x.dtype) y[1:-1] = x - d = diff(y) - #print 'd', d - up = find(d == 1); - dn = find(d == -1); + dif = npy.diff(y) + up = (dif == 1).nonzero()[0]; + dn = (dif == -1).nonzero()[0]; + i = (dn-up == max(dn - up)).nonzero()[0][0] + ind = npy.arange(up[i], dn[i]) - #print 'dn', dn, 'up', up, - ind = find( dn-up == max(dn - up)) - # pick the first - if iterable(ind): ind = ind[0] - ind = arange(up[ind], dn[ind]) - return ind +def longest_ones(x): + '''alias for longest_contiguous_ones''' + return longest_contiguous_ones(x) + def prepca(P, frac=0): """ Compute the principal components of P. P is a numVars x - numObservations numeric array. frac is the minimum fraction of - variance that a component must contain to be included + numObs array. frac is the minimum fraction of + variance that a component must contain to be included. Return value are - Pcomponents : a num components x num observations numeric array + Pcomponents : a numVars x numObs array Trans : the weights matrix, ie, Pcomponents = Trans*P fracVar : the fraction of the variance accounted for by each component returned + + A similar function of the same name was in the Matlab (TM) + R13 Neural Network Toolbox but is not found in later versions; + its successor seems to be called "processpcs". """ - U,s,v = svd(P) + U,s,v = npy.linalg.svd(P) varEach = s**2/P.shape[1] - totVar = asum(varEach) - fracVar = divide(varEach,totVar) - ind = int(asum(fracVar>=frac)) - + totVar = varEach.sum() + fracVar = varEach/totVar + ind = slice((fracVar>=frac).sum()) # select the components that are greater - Trans = transpose(U[:,:ind]) + Trans = U[:,ind].transpose() # The transformed data - Pcomponents = matrixmultiply(Trans,P) - return Pcomponents, Trans, fracVar[:ind] + Pcomponents = npy.dot(Trans,P) + return Pcomponents, Trans, fracVar[ind] def prctile(x, p = (0.0, 25.0, 50.0, 75.0, 100.0)): """ Return the percentiles of x. p can either be a sequence of - percentil values or a scalar. If p is a sequence the i-th element - of the return sequence is the p(i)-th percentile of x - + percentile values or a scalar. If p is a sequence the i-th element + of the return sequence is the p(i)-th percentile of x. + If p is a scalar, the largest value of x less than or equal + to the p percentage point in the sequence is returned. """ - x = sort(ravel(x)) + x = npy.ravel(x) + x.sort() Nx = len(x) - if not iterable(p): + if not cbook.iterable(p): return x[int(p*Nx/100.0)] - p = multiply(array(p), Nx/100.0) + p = npy.asarray(p)* Nx/100.0 ind = p.astype(int) - ind = where(ind>=Nx, Nx-1, ind) - return take(x, ind) + ind = npy.where(ind>=Nx, Nx-1, ind) + return x.take(ind) def prctile_rank(x, p): - """ - return the for each element in x, return the rank 0..len(p) . Eg - if p=(25, 50, 75), the return value will be a len(x) array with - values in [0,1,2,3] where 0 indicates the value is less than the - 25th percentile, 1 indicates the value is >= the 25th and < 50th - percentile, ... and 3 indicates the value is above the 75th - percentile cutoff + """ + return the for each element in x, return the rank 0..len(p) . Eg + if p=(25, 50, 75), the return value will be a len(x) array with + values in [0,1,2,3] where 0 indicates the value is less than the + 25th percentile, 1 indicates the value is >= the 25th and < 50th + percentile, ... and 3 indicates the value is above the 75th + percentile cutoff - p is either an array of percentiles in [0..100] or a scalar which - indicates how many quantiles of data you want ranked - """ + p is either an array of percentiles in [0..100] or a scalar which + indicates how many quantiles of data you want ranked + """ - if not iterable(p): - p = nx.arange(100./p, 100., 100./p) + if not cbook.iterable(p): + p = npy.arange(100.0/p, 100.0, 100.0/p) + else: + p = npy.asarray(p) - if max(p)<=1 or min(p)<0 or max(p)>100: - raise ValueError('percentiles should be in range 0..100, not 0..1') + if p.max()<=1 or p.min()<0 or p.max()>100: + raise ValueError('percentiles should be in range 0..100, not 0..1') - ptiles = prctile(x, p) - return nx.searchsorted(ptiles, x) + ptiles = prctile(x, p) + return npy.searchsorted(ptiles, x) def center_matrix(M, dim=0): """ Return the matrix M with each row having zero mean and unit std - if dim=1, center columns rather than rows + if dim=1 operate on columns instead of rows. (dim is opposite + to the numpy axis kwarg.) """ - # todo: implement this w/o loop. Allow optional arg to specify - # dimension to remove the mean from - if dim==1: M = transpose(M) - M = array(M, float) - if len(M.shape)==1 or M.shape[0]==1 or M.shape[1]==1: - M = M-mean(M) - sigma = std(M) - if sigma>0: - M = divide(M, sigma) - if dim==1: M=transpose(M) - return M - - for i in range(M.shape[0]): - M[i] -= mean(M[i]) - sigma = std(M[i]) - if sigma>0: - M[i] = divide(M[i], sigma) - if dim==1: M=transpose(M) + M = npy.asarray(M, npy.float_) + if dim: + M = (M - M.mean(axis=0)) / M.std(axis=0) + else: + M = (M - M.mean(axis=1)[:,npy.newaxis]) + M = M / M.std(axis=1)[:,npy.newaxis] return M @@ -895,101 +895,35 @@ If you have access to scipy, you should probably be using the - scipy.integrate tools rather than this function + scipy.integrate tools rather than this function. """ try: Ny = len(y0) except TypeError: - yout = zeros( (len(t),), float) + yout = npy.zeros( (len(t),), npy.float_) else: - yout = zeros( (len(t), Ny), float) + yout = npy.zeros( (len(t), Ny), npy.float_) yout[0] = y0 i = 0 - for i in arange(len(t)-1): + for i in npy.arange(len(t)-1): thist = t[i] dt = t[i+1] - thist dt2 = dt/2.0 y0 = yout[i] - k1 = asarray(derivs(y0, thist)) - k2 = asarray(derivs(y0 + dt2*k1, thist+dt2)) - k3 = asarray(derivs(y0 + dt2*k2, thist+dt2)) - k4 = asarray(derivs(y0 + dt*k3, thist+dt)) + k1 = npy.asarray(derivs(y0, thist)) + k2 = npy.asarray(derivs(y0 + dt2*k1, thist+dt2)) + k3 = npy.asarray(derivs(y0 + dt2*k2, thist+dt2)) + k4 = npy.asarray(derivs(y0 + dt*k3, thist+dt)) yout[i+1] = y0 + dt/6.0*(k1 + 2*k2 + 2*k3 + k4) return yout - - -def specgram(x, NFFT=256, Fs=2, detrend=detrend_none, - window=window_hanning, noverlap=128): - """ - Compute a spectrogram of data in x. Data are split into NFFT - length segements and the PSD of each section is computed. The - windowing function window is applied to each segment, and the - amount of overlap of each segment is specified with noverlap. - - window can be a function or a vector of length NFFT. To create - window vectors see numpy.blackman, numpy.hamming, numpy.bartlett, - scipy.signal, scipy.signal.get_window etc. - - - See pdf for more info. - - If x is real (i.e. non-Complex) only the positive spectrum is - given. If x is Complex then the complete spectrum is given. - - The returned times are the midpoints of the intervals over which - the ffts are calculated - """ - x = asarray(x) - assert(NFFT>noverlap) - if log(NFFT)/log(2) != int(log(NFFT)/log(2)): - raise ValueError, 'NFFT must be a power of 2' - - # zero pad x up to NFFT if it is shorter than NFFT - if len(x)<NFFT: - n = len(x) - x = resize(x, (NFFT,)) - x[n:] = 0 - - - # for real x, ignore the negative frequencies - if npy.iscomplexobj(x): numFreqs=NFFT - else: numFreqs = NFFT//2+1 - - if iterable(window): - assert(len(window) == NFFT) - windowVals = window - else: - windowVals = window(ones((NFFT,),typecode(x))) - step = NFFT-noverlap - ind = arange(0,len(x)-NFFT+1,step) - n = len(ind) - Pxx = zeros((numFreqs,n), float) - # do the ffts of the slices - - for i in range(n): - thisX = x[ind[i]:ind[i]+NFFT] - thisX = windowVals*detrend(thisX) - fx = absolute(fft(thisX))**2 - # Scale the spectrum by the norm of the window to compensate for - # windowing loss; see Bendat & Piersol Sec 11.5.2 - Pxx[:,i] = divide(fx[:numFreqs], norm(windowVals)**2) - t = 1/Fs*(ind+NFFT/2) - freqs = Fs/NFFT*arange(numFreqs) - - if npy.iscomplexobj(x): - freqs = concatenate((freqs[NFFT/2:]-Fs,freqs[:NFFT/2])) - Pxx = concatenate((Pxx[NFFT/2:,:],Pxx[:NFFT/2,:]),0) - - return Pxx, freqs, t - def bivariate_normal(X, Y, sigmax=1.0, sigmay=1.0, mux=0.0, muy=0.0, sigmaxy=0.0): """ @@ -1002,7 +936,8 @@ rho = sigmaxy/(sigmax*sigmay) z = Xmu**2/sigmax**2 + Ymu**2/sigmay**2 - 2*rho*Xmu*Ymu/(sigmax*sigmay) - return 1.0/(2*pi*sigmax*sigmay*numerix.mlab.sqrt(1-rho**2)) * exp( -z/(2*(1-rho**2))) + denom = 2*npy.pi*sigmax*sigmay*npy.sqrt(1-rho**2) + return npy.exp( -z/(2*(1-rho**2))) / denom @@ -1014,37 +949,22 @@ where x and y are the indices into Z and z are the values of Z at those indices. x,y,z are 1D arrays """ + X,Y = npy.indices(z.shape) + return X[Cond], Y[Cond], Z[Cond] - M,N = Z.shape - z = ravel(Z) - ind, = npy.nonzero( ravel(Cond) ) - - x = arange(M); x.shape = M,1 - X = repeat(x, N, 1) - x = ravel(X) - - y = arange(N); y.shape = 1,N - Y = repeat(y, M) - y = ravel(Y) - - x = take(x, ind) - y = take(y, ind) - z = take(z, ind) - return x,y,z - def get_sparse_matrix(M,N,frac=0.1): 'return a MxN sparse matrix with frac elements randomly filled' - data = zeros((M,N))*0. + data = npy.zeros((M,N))*0. for i in range(int(M*N*frac)): - x = random.randint(0,M-1) - y = random.randint(0,N-1) - data[x,y] = rand() + x = npy.random.randint(0,M-1) + y = npy.random.randint(0,N-1) + data[x,y] = npy.random.rand() return data def dist(x,y): 'return the distance between two points' d = x-y - return numerix.mlab.sqrt(dot(d,d)) + return npy.sqrt(npy.dot(d,d)) def dist_point_to_segment(p, s0, s1): """ @@ -1055,17 +975,17 @@ This algorithm from http://softsurfer.com/Archive/algorithm_0102/algorithm_0102.htm#Distance%20to%20Ray%20or%20Segment """ - p = asarray(p, float) - s0 = asarray(s0, float) - s1 = asarray(s1, float) + p = npy.asarray(p, npy.float_) + s0 = npy.asarray(s0, npy.float_) + s1 = npy.asarray(s1, npy.float_) v = s1 - s0 w = p - s0 - c1 = dot(w,v); + c1 = npy.dot(w,v); if ( c1 <= 0 ): return dist(p, s0); - c2 = dot(v,v) + c2 = npy.dot(v,v) if ( c2 <= c1 ): return dist(p, s1); @@ -1076,7 +996,7 @@ def segments_intersect(s1, s2): """ Return True if s1 and s2 intersect. - s1 and s2 are defines as + s1 and s2 are defined as s1: (x1, y1), (x2, y2) s2: (x3, y3), (x4, y4) @@ -1104,29 +1024,33 @@ """ Compute an FFT phase randomized surrogate of x """ - if iterable(window): - x=window*detrend(x) + if cbook.iterable(window): + x=window*detrend(x) else: - x = window(detrend(x)) - z = fft(x) - a = 2.*pi*1j - phase = a*rand(len(x)) - z = z*exp(phase) - return inverse_fft(z).real + x = window(detrend(x)) + z = npy.fft.fft(x) + a = 2.*npy.pi*1j + phase = a * npy.random.rand(len(x)) + z = z*npy.exp(phase) + return npy.fft.ifft(z).real def liaupunov(x, fprime): - """ - x is a very long trajectory from a map, and fprime returns the - derivative of x. Return lambda = 1/n\sum ln|fprime(x_i)|. See Sec - 10.5 Strogatz (1994)"Nonlinear Dynamics and Chaos". - """ - return mean(log(fprime(x))) + """ + x is a very long trajectory from a map, and fprime returns the + derivative of x. Return lambda = 1/n\sum ln|fprime(x_i)|. See Sec + 10.5 Strogatz (1994)"Nonlinear Dynamics and Chaos". + See also http://en.wikipedia.org/wiki/Lyapunov_exponent. + What the function here calculates may not be what you really want; + caveat emptor. + It also seems that this function's name is badly misspelled. + """ + return npy.mean(npy.log(npy.absolute(fprime(x)))) class FIFOBuffer: """ A FIFO queue to hold incoming x, y data in a rotating buffer using - numerix arrrays under the hood. It is assumed that you will call + numpy arrays under the hood. It is assumed that you will call asarrays much less frequently than you add data to the queue -- otherwise another data structure will be faster @@ -1138,13 +1062,15 @@ the dataLim will be updated as new data come in TODI: add a grow method that will extend nmax + + mlab seems like the wrong place for this class. """ def __init__(self, nmax): 'buffer up to nmax points' - self._xa = nx.zeros((nmax,), typecode=float) - self._ya = nx.zeros((nmax,), typecode=float) - self._xs = nx.zeros((nmax,), typecode=float) - self._ys = nx.zeros((nmax,), typecode=float) + self._xa = npy.zeros((nmax,), npy.float_) + self._ya = npy.zeros((nmax,), npy.float_) + self._xs = npy.zeros((nmax,), npy.float_) + self._ys = npy.zeros((nmax,), npy.float_) self._ind = 0 self._nmax = nmax self.dataLim = None @@ -1157,17 +1083,17 @@ def add(self, x, y): 'add scalar x and y to the queue' if self.dataLim is not None: - xys = ((x,y),) - self.dataLim.update(xys, -1) #-1 means use the default ignore setting + xys = ((x,y),) + self.dataLim.update(xys, -1) #-1 means use the default ignore setting ind = self._ind % self._nmax #print 'adding to fifo:', ind, x, y self._xs[ind] = x self._ys[ind] = y for N,funcs in self.callbackd.items(): - if (self._ind%N)==0: - for func in funcs: - func(self) + if (self._ind%N)==0: + for func in funcs: + func(self) self._ind += 1 @@ -1202,14 +1128,9 @@ def movavg(x,n): 'compute the len(n) moving average of x' - n = int(n) - N = len(x) - assert(N>n) - y = zeros(N-(n-1),float) - for i in range(n): - y += x[i:N-(n-1)+i] - y /= float(n) - return y + w = npy.empty((n,), dtype=npy.float_) + w[:] = 1.0/n + return npy.convolve(x, w, mode='valid') def save(fname, X, fmt='%.18e',delimiter=' '): """ @@ -1231,7 +1152,7 @@ comma-separated values """ - if is_string_like(fname): + if cbook.is_string_like(fname): if fname.endswith('.gz'): import gzip fh = gzip.open(fname,'wb') @@ -1243,9 +1164,9 @@ raise ValueError('fname must be a string or file handle') - X = asarray(X) + X = npy.asarray(X) origShape = None - if len(X.shape)==1: + if X.ndim == 1: origShape = X.shape X.shape = len(X), 1 for row in X: @@ -1267,8 +1188,7 @@ fname can be a filename or a file handle. Support for gzipped files is automatic, if the filename ends in .gz - matfile data is not currently supported, but see - Nigel Wade's matfile ftp://ion.le.ac.uk/matfile/matfile.tar.gz + matfile data is not supported; use scipy.io.mio module Example usage: @@ -1308,7 +1228,7 @@ """ if converters is None: converters = {} - fh = to_filehandle(fname) + fh = cbook.to_filehandle(fname) X = [] converterseq = None @@ -1317,20 +1237,22 @@ line = line[:line.find(comments)].strip() if not len(line): continue if converterseq is None: - converterseq = [converters.get(j,float) for j,val in enumerate(line.split(delimiter))] + converterseq = [converters.get(j,float) + for j,val in enumerate(line.split(delimiter))] if usecols is not None: vals = line.split(delimiter) row = [converterseq[j](vals[j]) for j in usecols] else: - row = [converterseq[j](val) for j,val in enumerate(line.split(delimiter))] + row = [converterseq[j](val) + for j,val in enumerate(line.split(delimiter))] thisLen = len(row) X.append(row) - X = array(X, float) + X = npy.array(X, npy.float_) r,c = X.shape if r==1 or c==1: - X.shape = max([r,c]), - if unpack: return transpose(X) + X.shape = max(r,c), + if unpack: X.transpose() else: return X def csv2rec(fname, comments='#', skiprows=0, checkrows=5, delimiter=',', @@ -1360,20 +1282,16 @@ converterd, if not None, is a dictionary mapping column number or munged column name to a converter function - See examples/loadrec.py """ - - if converterd is None: converterd = dict() import dateutil.parser parsedate = dateutil.parser.parse - - fh = to_filehandle(fname) + fh = cbook.to_filehandle(fname) reader = csv.reader(fh, delimiter=delimiter) def process_skiprows(reader): @@ -1386,8 +1304,6 @@ process_skiprows(reader) - - def get_func(item, func): # promote functions in this order funcmap = {int:float, float:dateutil.parser.parse, dateutil.parser.parse:str} @@ -1420,9 +1336,7 @@ converters[j] = func return converters - # Get header and remove invalid characters - needheader = names is None if needheader: headers = reader.next() @@ -1445,8 +1359,6 @@ names.append(item) seen[item] = cnt+1 - - # get the converter functions by inspecting checkrows converters = get_converters(reader) if converters is None: @@ -1497,10 +1409,10 @@ Icelandic Meteorological Office, March 2006 halldor at vedur.is) """ # Cast key variables as float. - x=nx.asarray(x, float) - y=nx.asarray(y, float) + x=npy.asarray(x, npy.float_) + y=npy.asarray(y, npy.float_) - yp=nx.zeros(y.shape, float) + yp=npy.zeros(y.shape, npy.float_) dx=x[1:] - x[:-1] dy=y[1:] - y[:-1] @@ -1529,7 +1441,7 @@ The interpolation method is described in the article A CONSISTENTLY WELL BEHAVED METHOD OF INTERPOLATION by Russell W. Stineman. The article appeared in the July 1980 issue of - Creative computing with a note from the editor stating that while + Creative Computing with a note from the editor stating that while they were not an academic journal but once in a while something serious @@ -1555,18 +1467,18 @@ """ # Cast key variables as float. - x=nx.asarray(x, float) - y=nx.asarray(y, float) + x=npy.asarray(x, npy.float_) + y=npy.asarray(y, npy.float_) assert x.shape == y.shape N=len(y) if yp is None: yp = slopes(x,y) else: - yp=nx.asarray(yp, float) + yp=npy.asarray(yp, npy.float_) - xi=nx.asarray(xi, float) - yi=nx.zeros(xi.shape, float) + xi=npy.asarray(xi, npy.float_) + yi=npy.zeros(xi.shape, npy.float_) # calculate linear slopes dx = x[1:] - x[:-1] @@ -1575,83 +1487,39 @@ # find the segment each xi is in # this line actually is the key to the efficiency of this implementation - idx = nx.searchsorted(x[1:-1], xi) + idx = npy.searchsorted(x[1:-1], xi) # now we have generally: x[idx[j]] <= xi[j] <= x[idx[j]+1] # except at the boundaries, where it may be that xi[j] < x[0] or xi[j] > x[-1] # the y-values that would come out from a linear interpolation: - sidx = nx.take(s, idx) - xidx = nx.take(x, idx) - yidx = nx.take(y, idx) - xidxp1 = nx.take(x, idx+1) + sidx = s.take(idx) + xidx = x.take(idx) + yidx = y.take(idx) + xidxp1 = x.take(idx+1) yo = yidx + sidx * (xi - xidx) # the difference that comes when using the slopes given in yp - dy1 = (nx.take(yp, idx)- sidx) * (xi - xidx) # using the yp slope of the left point - dy2 = (nx.take(yp, idx+1)-sidx) * (xi - xidxp1) # using the yp slope of the right point + dy1 = (yp.take(idx)- sidx) * (xi - xidx) # using the yp slope of the left point + dy2 = (yp.take(idx+1)-sidx) * (xi - xidxp1) # using the yp slope of the right point dy1dy2 = dy1*dy2 # The following is optimized for Python. The solution actually # does more calculations than necessary but exploiting the power # of numpy, this is far more efficient than coding a loop by hand # in Python - yi = yo + dy1dy2 * nx.choose(nx.array(nx.sign(dy1dy2), nx.int32)+1, + yi = yo + dy1dy2 * npy.choose(npy.array(npy.sign(dy1dy2), npy.int32)+1, ((2*xi-xidx-xidxp1)/((dy1-dy2)*(xidxp1-xidx)), 0.0, 1/(dy1+dy2),)) - return yi -def _inside_poly_deprecated(points, verts): - """ - # use nxutils.points_inside_poly instead - points is a sequence of x,y points - verts is a sequence of x,y vertices of a poygon - - return value is a sequence on indices into points for the points - that are inside the polygon - """ - xys = nx.asarray(points) - Nxy = xys.shape[0] - Nv = len(verts) - - def angle(x1, y1, x2, y2): - twopi = 2*nx.pi - theta1 = nx.arctan2(y1, x1) - theta2 = nx.arctan2(y2, x2) - dtheta = theta2-theta1 - d = dtheta%twopi - d = nx.where(nx.less(d, 0), twopi + d, d) - return nx.where(nx.greater(d,nx.pi), d-twopi, d) - - angles = nx.zeros((Nxy,), float) - x1 = nx.zeros((Nxy,), float) - y1 = nx.zeros((Nxy,), float) - x2 = nx.zeros((Nxy,), float) - y2 = nx.zeros((Nxy,), float) - x = xys[:,0] - y = xys[:,1] - for i in range(Nv): - thisx, thisy = verts[i] - x1 = thisx - x - y1 = thisy - y - thisx, thisy = verts[(i+1)%Nv] - x2 = thisx - x - y2 = thisy - y - - a = angle(x1, y1, x2, y2) - angles += a - res, = npy.nonzero(nx.greater_equal(nx.absolute(angles), nx.pi)) - return res - - def inside_poly(points, verts): """ points is a sequence of x,y points verts is a sequence of x,y vertices of a poygon - return value is a sequence on indices into points for the points + return value is a sequence of indices into points for the points that are inside the polygon """ res, = npy.nonzero(nxutils.points_inside_poly(points, verts)) @@ -1689,10 +1557,10 @@ return value is x, y arrays for use with Axes.fill """ Nx = len(x) - if not iterable(ylower): + if not cbook.iterable(ylower): ylower = ylower*npy.ones(Nx) - if not iterable(yupper): + if not cbook.iterable(yupper): yupper = yupper*npy.ones(Nx) x = npy.concatenate( (x, x[::-1]) ) @@ -1757,12 +1625,12 @@ def exp_safe(x): """Compute exponentials which safely underflow to zero. - Slow but convenient to use. Note that NumArray will introduce proper + Slow but convenient to use. Note that numpy provides proper floating point exception handling with access to the underlying hardware.""" if type(x) is npy.ndarray: - return exp(clip(x,exp_safe_MIN,exp_safe_MAX)) + return exp(npy.clip(x,exp_safe_MIN,exp_safe_MAX)) else: return math.exp(x) @@ -1770,66 +1638,68 @@ """amap(function, sequence[, sequence, ...]) -> array. Works like map(), but it returns an array. This is just a convenient - shorthand for Numeric.array(map(...))""" - return array(map(fn,*args)) + shorthand for numpy.array(map(...)) + """ + return npy.array(map(fn,*args)) +#from numpy import zeros_like def zeros_like(a): """Return an array of zeros of the shape and typecode of a.""" + warnings.warn("Use numpy.zeros_like(a)", DeprecationWarning) + return npy.zeros_like(a) - return zeros(a.shape,typecode(a)) - +#from numpy import sum as sum_flat def sum_flat(a): """Return the sum of all the elements of a, flattened out. It uses a.flat, and if a is not contiguous, a call to ravel(a) is made.""" + warnings.warn("Use numpy.sum(a) or a.sum()", DeprecationWarning) + return npy.sum(a) - if iscontiguous(a): - return asum(a.flat) - else: - return asum(ravel(a)) - +#from numpy import mean as mean_flat def mean_flat(a): """Return the mean of all the elements of a, flattened out.""" + warnings.warn("Use numpy.mean(a) or a.mean()", DeprecationWarning) + return npy.mean(a) - return sum_flat(a)/float(size(a)) - def rms_flat(a): """Return the root mean square of all the elements of a, flattened out.""" - return numerix.mlab.sqrt(sum_flat(absolute(a)**2)/float(size(a))) + return npy.sqrt(npy.mean(npy.absolute(a)**2)) def l1norm(a): """Return the l1 norm of a, flattened out. Implemented as a separate function (not a call to norm() for speed).""" - return sum_flat(absolute(a)) + return npy.sum(npy.absolute(a)) def l2norm(a): """Return the l2 norm of a, flattened out. Implemented as a separate function (not a call to norm() for speed).""" - return numerix.mlab.sqrt(sum_flat(absolute(a)**2)) + return npy.sqrt(npy.sum(npy.absolute(a)**2)) -def norm(a,p=2): +def norm_flat(a,p=2): """norm(a,p=2) -> l-p norm of a.flat Return the l-p norm of a, considered as a flat array. This is NOT a true matrix norm, since arrays of arbitrary rank are always flattened. p can be a number or the string 'Infinity' to get the L-infinity norm.""" - + # This function was being masked by a more general norm later in + # the file. We may want to simply delete it. if p=='Infinity': - return max(absolute(a).flat) + return npy.amax(npy.absolute(a)) else: - return (sum_flat(absolute(a)**p))**(1.0/p) + return (npy.sum(npy.absolute(a)**p))**(1.0/p) def frange(xini,xfin=None,delta=None,**kw): """frange([start,] stop[, step, keywords]) -> array of floats - Return a Numeric array() containing a progression of floats. Similar to + Return a numpy ndarray containing a progression of floats. Similar to arange(), but defaults to a closed interval. frange(x0, x1) returns [x0, x0+1, x0+2, ..., x1]; start defaults to 0, and @@ -1855,7 +1725,7 @@ >>> frange(3,closed=0) array([ 0., 1., 2.]) >>> frange(1,6,2) - array([1, 3, 5]) + array([1, 3, 5]) or 1,3,5,7, depending on floating point vagueries >>> frange(1,6.5,npts=5) array([ 1. , 2.375, 3.75 , 5.125, 6.5 ]) """ @@ -1879,19 +1749,22 @@ npts=kw['npts'] delta=(xfin-xini)/float(npts-endpoint) except KeyError: - # round() gets npts right even with the vagaries of floating point... [truncated message content] |
From: <md...@us...> - 2007-08-13 15:31:15
|
Revision: 3706 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3706&view=rev Author: mdboom Date: 2007-08-13 08:19:11 -0700 (Mon, 13 Aug 2007) Log Message: ----------- Make horizontal line drawing more consistent across all backends. Fix but in ft2font glyph rendering for glyphs with a left offset. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/src/ft2font.cpp Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-13 14:32:15 UTC (rev 3705) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-13 15:19:11 UTC (rev 3706) @@ -253,9 +253,7 @@ def render_rect_filled(self, x1, y1, x2, y2): font = self.fonts_object.get_fonts()[0] - font.draw_rect_filled( - int(x1 + 0.5), int(y1 + 0.5) - 1, - int(x2 - 0.5), int(y2 - 0.5) - 1) + font.draw_rect_filled(x1, y1, x2, y2 - 1) def get_results(self): return (self.width, @@ -329,7 +327,7 @@ def render_rect_filled(self, x1, y1, x2, y2): self.svg_rects.append( - (x1, self.height - y2, x2 - x1, y2 - y1)) + (x1, self.height - y1 + 1, x2 - x1, y2 - y1)) def get_results(self): svg_elements = Bunch(svg_glyphs = self.svg_glyphs, @@ -559,8 +557,7 @@ def get_underline_thickness(self, font, fontsize, dpi): cached_font = self._get_font(font) - cached_font.font.set_size(fontsize, dpi) - return max(1.0, cached_font.font.underline_thickness / 64.0) + return max(1.0, cached_font.font.underline_thickness / 64.0 / fontsize * 10.0) def get_kern(self, font1, sym1, fontsize1, font2, sym2, fontsize2, dpi): @@ -1102,10 +1099,18 @@ self.height = metrics.ymax - metrics.ymin self.depth = 0 + def shrink(self): + Char.shrink(self) + self._update_metrics() + + def grow(self): + Char.grow(self) + self._update_metrics() + def render(self, x, y): """Render the character to the canvas""" self.font_output.render_glyph( - x, y + (self._metrics.ymax - self.height), + x - self._metrics.xmin, y + self._metrics.ymin, self.font, self.c, self.fontsize, self.dpi) class List(Box): @@ -2264,8 +2269,8 @@ metrics = state.font_output.get_metrics( state.font, '=', state.fontsize, state.dpi) shift = (cden.height - - (metrics.ymax + metrics.ymin) / 2 + - thickness * 2.5) + ((metrics.ymax + metrics.ymin) / 2 - + thickness * 3.0)) vlist.shift_amount = shift hlist = Hlist([vlist, Hbox(thickness * 2.)]) @@ -2316,7 +2321,6 @@ # Negative kerning to put root over tick Kern(-check.width * 0.5), check, # Check - Kern(-thickness * 0.3), # Push check into rule slightly rightside]) # Body return [hlist] Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007-08-13 14:32:15 UTC (rev 3705) +++ trunk/matplotlib/src/ft2font.cpp 2007-08-13 15:19:11 UTC (rev 3706) @@ -1219,7 +1219,7 @@ FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[glyph->glyphInd]; - draw_bitmap( &bitmap->bitmap, x, y); + draw_bitmap( &bitmap->bitmap, x + bitmap->left, y); return Py::Object(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ef...@us...> - 2007-08-14 07:07:48
|
Revision: 3707 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3707&view=rev Author: efiring Date: 2007-08-14 00:07:45 -0700 (Tue, 14 Aug 2007) Log Message: ----------- Use pickle to cache entire fontManager instance. Call font_manager.findfont() instead of font_manager.fontManager.findfont(). Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/examples/fonts_demo.py trunk/matplotlib/examples/fonts_demo_kw.py trunk/matplotlib/lib/matplotlib/backends/backend_agg.py trunk/matplotlib/lib/matplotlib/backends/backend_agg2.py trunk/matplotlib/lib/matplotlib/backends/backend_emf.py trunk/matplotlib/lib/matplotlib/backends/backend_gd.py trunk/matplotlib/lib/matplotlib/backends/backend_paint.py trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py trunk/matplotlib/lib/matplotlib/backends/backend_ps.py trunk/matplotlib/lib/matplotlib/backends/backend_qt.py trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py trunk/matplotlib/lib/matplotlib/backends/backend_svg.py trunk/matplotlib/lib/matplotlib/font_manager.py trunk/matplotlib/lib/matplotlib/mathtext.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/CHANGELOG 2007-08-14 07:07:45 UTC (rev 3707) @@ -1,3 +1,7 @@ +2007-08-13 Use pickle to cache entire fontManager; change to using + font_manager module-level function findfont wrapper for + the fontManager.findfont method - EF + 2007-08-11 Numpification and cleanup of mlab.py and some examples - EF 2007-08-06 Removed mathtext2 Modified: trunk/matplotlib/examples/fonts_demo.py =================================================================== --- trunk/matplotlib/examples/fonts_demo.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/examples/fonts_demo.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -3,9 +3,9 @@ Show how to set custom font properties. For interactive users, you can also use kwargs to the text command, -which requires less typing. See exampes/fonts_demo_kw.py +which requires less typing. See examples/fonts_demo_kw.py """ -from matplotlib.font_manager import fontManager, FontProperties +from matplotlib.font_manager import FontProperties from pylab import * subplot(111, axisbg='w') Modified: trunk/matplotlib/examples/fonts_demo_kw.py =================================================================== --- trunk/matplotlib/examples/fonts_demo_kw.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/examples/fonts_demo_kw.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -4,7 +4,7 @@ style of coding, see examples/fonts_demo.py. """ -from matplotlib.font_manager import fontManager, FontProperties +from matplotlib.font_manager import FontProperties from pylab import * subplot(111, axisbg='w') Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -81,7 +81,7 @@ GraphicsContextBase, FigureManagerBase, FigureCanvasBase from matplotlib.cbook import enumerate, is_string_like, exception_to_str from matplotlib.figure import Figure -from matplotlib.font_manager import fontManager +from matplotlib.font_manager import findfont from matplotlib.ft2font import FT2Font, LOAD_DEFAULT from matplotlib.mathtext import math_parse_s_ft2font from matplotlib.transforms import lbwh_to_bbox @@ -175,7 +175,7 @@ 'debug-annoying') width, height, fonts, used_characters = math_parse_s_ft2font( s, self.dpi.get(), prop) - + if angle == 90: width, height = height, width for font in fonts: @@ -297,7 +297,7 @@ font = _fontd.get(key) if font is None: - fname = fontManager.findfont(prop) + fname = findfont(prop) font = FT2Font(str(fname)) _fontd[key] = font Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg2.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_agg2.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/backends/backend_agg2.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -15,7 +15,6 @@ from matplotlib.cbook import enumerate, is_string_like, exception_to_str from matplotlib.figure import Figure -from matplotlib.font_manager import fontManager from matplotlib.ft2font import FT2Font from matplotlib.mathtext import math_parse_s_ft2font Modified: trunk/matplotlib/lib/matplotlib/backends/backend_emf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_emf.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/backends/backend_emf.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -23,7 +23,7 @@ from matplotlib.figure import Figure from matplotlib.transforms import Bbox -from matplotlib.font_manager import fontManager, FontProperties +from matplotlib.font_manager import findfont, FontProperties from matplotlib.ft2font import FT2Font, KERNING_UNFITTED, KERNING_DEFAULT, KERNING_UNSCALED # Font handling stuff snarfed from backend_ps, but only using TTF fonts @@ -473,7 +473,7 @@ key = hash(prop) font = _fontd.get(key) if font is None: - fname = fontManager.findfont(prop) + fname = findfont(prop) if debugText: print "_get_font_ttf: name=%s" % fname font = FT2Font(str(fname)) _fontd[key] = font Modified: trunk/matplotlib/lib/matplotlib/backends/backend_gd.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_gd.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/backends/backend_gd.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -22,7 +22,7 @@ from matplotlib.colors import colorConverter from matplotlib.figure import Figure from matplotlib.transforms import Bbox -from matplotlib.font_manager import fontManager +from matplotlib.font_manager import findfont # support old font names if (os.environ.has_key('GDFONTPATH') and not os.environ.has_key('TTFPATH')): @@ -66,7 +66,7 @@ """ size = prop.get_size_in_points() - font = fontManager.findfont(prop) + font = findfont(prop) scale = self.get_text_scale() try: @@ -176,7 +176,7 @@ """ size = prop.get_size_in_points() - font = fontManager.findfont(prop) + font = findfont(prop) x = int(x) y = int(y) Modified: trunk/matplotlib/lib/matplotlib/backends/backend_paint.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_paint.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/backends/backend_paint.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -28,7 +28,7 @@ from matplotlib.figure import Figure from matplotlib.text import Text, _process_text_args -from matplotlib.font_manager import fontManager +from matplotlib.font_manager import findfont """ @@ -106,7 +106,7 @@ Get the paint font for text instance t, cacheing for efficiency """ - fname = fontManager.findfont(prop) + fname = findfont(prop) size = self.get_text_scale() * prop.get_size_in_points() props = fname, size, angle Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -24,7 +24,7 @@ FigureManagerBase, FigureCanvasBase from matplotlib.cbook import Bunch, enumerate, is_string_like, reverse_dict, get_realpath_and_stat from matplotlib.figure import Figure -from matplotlib.font_manager import fontManager +from matplotlib.font_manager import findfont from matplotlib.afm import AFM from matplotlib.dviread import Dvi from matplotlib.ft2font import FT2Font, FIXED_WIDTH, ITALIC, LOAD_NO_SCALE, \ @@ -441,9 +441,9 @@ if is_string_like(fontprop): filename = fontprop elif rcParams['pdf.use14corefonts']: - filename = fontManager.findfont(fontprop, fontext='afm') + filename = findfont(fontprop, fontext='afm') else: - filename = fontManager.findfont(fontprop) + filename = findfont(fontprop) Fx = self.fontNames.get(filename) if Fx is None: @@ -484,7 +484,7 @@ return "%s-%s" % ( os.path.splitext(os.path.basename(filename))[0], symbol_name) - + def embedTTF(self, filename, characters): """Embed the TTF font from the named file into the document.""" @@ -499,7 +499,7 @@ # boxes and the like if value < 0: return floor(value) else: return ceil(value) - + def embedTTFType3(font, characters, descriptor): """The Type 3-specific part of embedding a Truetype font""" widthsObject = self.reserveObject('font widths') @@ -509,7 +509,7 @@ differencesArray = [] firstchar, lastchar = 0, 255 bbox = [cvt(x, nearest=False) for x in font.bbox] - + fontdict = { 'Type' : Name('Font'), 'BaseFont' : ps_name, @@ -667,7 +667,7 @@ max_ccode = max(ccode, max_ccode) widths.sort() cid_to_gid_map = cid_to_gid_map[:max_ccode + 1] - + last_ccode = -2 w = [] max_width = 0 @@ -689,7 +689,7 @@ self.endStream() descriptor['MaxWidth'] = max_width - + # Write everything out self.writeObject(cidFontDictObject, cidFontDict) self.writeObject(type0FontDictObject, type0FontDict) @@ -699,7 +699,7 @@ return type0FontDictObject # Beginning of main embedTTF function... - + # You are lost in a maze of TrueType tables, all different... ps_name = Name(font.get_sfnt()[(1,0,0,6)]) pclt = font.get_sfnt_table('pclt') \ @@ -737,7 +737,7 @@ return embedTTFType3(font, characters, descriptor) elif fonttype == 42: return embedTTFType42(font, characters, descriptor) - + def alphaState(self, alpha): """Return name of an ExtGState that sets alpha to the given value""" @@ -987,7 +987,7 @@ self.encode_string = self.encode_string_type3 else: self.encode_string = self.encode_string_type42 - + def finalize(self): self.gc.finalize() del self.truetype_font_cache @@ -1020,7 +1020,7 @@ used_characters = self.used_characters.setdefault( stat_key, (realpath, Set())) used_characters[1].update(set) - + def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation): """ @@ -1187,7 +1187,7 @@ self.file.output(Op.gsave) self.file.output(cos(a), sin(a), -sin(a), cos(a), x, y, Op.concat_matrix) - + self.check_gc(gc, gc._rgb) self.file.output(Op.begin_text) prev_font = None, None @@ -1279,7 +1279,7 @@ def encode_string_type3(self, s): return s.encode('cp1252', 'replace') - + def encode_string_type42(self, s): return s.encode('utf-16be', 'replace') @@ -1296,7 +1296,7 @@ # use XObject command (Do). If using Type 42 fonts, all of # this complication is avoided, but of course, those fonts can # not be subsetted. - + if ismath: return self.draw_mathtext(gc, x, y, s, prop, angle) self.check_gc(gc, gc._rgb) @@ -1344,7 +1344,7 @@ Op.selectfont) self._setup_textpos(x, y, angle) self.file.output(self.encode_string(s), Op.show, Op.end_text) - + def draw_text_woven(chunks): """Outputs text using the woven method, alternating between chunks of 1-byte characters and 2-byte characters. @@ -1375,7 +1375,7 @@ self._setup_textpos(newx, 0, 0, oldx, 0, 0) self.file.output(self.encode_string(chunk), Op.show) oldx = newx - + lastgind = None for c in chunk: ccode = ord(c) @@ -1413,7 +1413,7 @@ return draw_text_simple() else: return draw_text_woven(chunks) - + def get_text_width_height(self, s, prop, ismath): # FT2Font can handle unicode, and so can we # if isinstance(s, unicode): @@ -1443,7 +1443,7 @@ key = hash(prop) font = self.afm_font_cache.get(key) if font is None: - filename = fontManager.findfont(prop, fontext='afm') + filename = findfont(prop, fontext='afm') fh = file(filename) font = AFM(fh) fh.close() @@ -1454,7 +1454,7 @@ key = hash(prop) font = self.truetype_font_cache.get(key) if font is None: - filename = fontManager.findfont(prop) + filename = findfont(prop) font = FT2Font(str(filename)) self.truetype_font_cache[key] = font font.clear() Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -18,7 +18,7 @@ from matplotlib.cbook import is_string_like, izip, get_realpath_and_stat from matplotlib.figure import Figure -from matplotlib.font_manager import fontManager +from matplotlib.font_manager import findfont from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_NO_HINTING from matplotlib.ttconv import convert_ttf_to_ps from matplotlib.mathtext import math_parse_s_ps @@ -158,7 +158,7 @@ used_characters = self.used_characters.setdefault( stat_key, (realpath, Set())) used_characters[1].update(set) - + def set_color(self, r, g, b, store=1): if (r,g,b) != self.color: if r==g and r==b: @@ -307,7 +307,7 @@ key = hash(prop) font = self.afmfontd.get(key) if font is None: - font = AFM(file(fontManager.findfont(prop, fontext='afm'))) + font = AFM(file(findfont(prop, fontext='afm'))) self.afmfontd[key] = font return font @@ -315,7 +315,7 @@ key = hash(prop) font = self.fontd.get(key) if font is None: - fname = fontManager.findfont(prop) + fname = findfont(prop) font = FT2Font(str(fname)) self.fontd[key] = font font.clear() Modified: trunk/matplotlib/lib/matplotlib/backends/backend_qt.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_qt.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/backends/backend_qt.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -6,7 +6,6 @@ import matplotlib from matplotlib import verbose from matplotlib.cbook import is_string_like, enumerate, onetrue -from matplotlib.font_manager import fontManager from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \ FigureManagerBase, FigureCanvasBase, NavigationToolbar2, cursors from matplotlib._pylab_helpers import Gcf Modified: trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -6,7 +6,6 @@ import matplotlib from matplotlib import verbose from matplotlib.cbook import is_string_like, enumerate, onetrue -from matplotlib.font_manager import fontManager from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \ FigureManagerBase, FigureCanvasBase, NavigationToolbar2, cursors from matplotlib._pylab_helpers import Gcf Modified: trunk/matplotlib/lib/matplotlib/backends/backend_svg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -7,7 +7,7 @@ FigureManagerBase, FigureCanvasBase from matplotlib.colors import rgb2hex from matplotlib.figure import Figure -from matplotlib.font_manager import fontManager, FontProperties +from matplotlib.font_manager import findfont, FontProperties from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_NO_HINTING from matplotlib.mathtext import math_parse_s_ft2font_svg @@ -57,7 +57,7 @@ key = hash(prop) font = _fontd.get(key) if font is None: - fname = fontManager.findfont(prop) + fname = findfont(prop) font = FT2Font(str(fname)) _fontd[key] = font font.clear() @@ -275,9 +275,9 @@ lastgind = gind currx += kern/64.0 - svg.append('<use xlink:href="#%s" transform="translate(%s)"/>\n' + svg.append('<use xlink:href="#%s" transform="translate(%s)"/>\n' % (charid, currx)) - + currx += (glyph.linearHoriAdvance / 65536.0) svg.append('</g>\n') svg = ''.join(svg) @@ -309,17 +309,17 @@ currx, curry = 0.0, 0.0 for step in glyph.path: if step[0] == 0: # MOVE_TO - path_data.append("m%s %s" % + path_data.append("m%s %s" % (step[1] - currx, -step[2] - curry)) elif step[0] == 1: # LINE_TO - path_data.append("l%s %s" % + path_data.append("l%s %s" % (step[1] - currx, -step[2] - curry)) elif step[0] == 2: # CURVE3 - path_data.append("q%s %s %s %s" % + path_data.append("q%s %s %s %s" % (step[1] - currx, -step[2] - curry, step[3] - currx, -step[4] - curry)) elif step[0] == 3: # CURVE4 - path_data.append("c%s %s %s %s %s %s" % + path_data.append("c%s %s %s %s %s %s" % (step[1] - currx, -step[2] - curry, step[3] - currx, -step[4] - curry, step[5] - currx, -step[6] - curry)) @@ -356,8 +356,8 @@ for font, fontsize, thetext, new_x, new_y_mtc, metrics in svg_glyphs: charid = self._add_char_def(font, thetext) - - svg.append('<use xlink:href="#%s" transform="translate(%s, %s) scale(%s)"/>\n' % + + svg.append('<use xlink:href="#%s" transform="translate(%s, %s) scale(%s)"/>\n' % (charid, new_x, -new_y_mtc, fontsize / self.FONT_SCALE)) svg.append('</g>\n') else: # not rcParams['svg.embed_char_paths'] @@ -373,7 +373,7 @@ for font, fontsize, thetext, new_x, new_y_mtc, metrics in svg_glyphs: new_y = - new_y_mtc - svg.append('<tspan style="font-size: %f; font-family: %s"' % + svg.append('<tspan style="font-size: %f; font-family: %s"' % (fontsize, font.family_name)) xadvance = metrics.advance svg.append(' textLength="%f"' % xadvance) @@ -387,7 +387,7 @@ svg.append(' dy="%f"' % dy) thetext = escape_xml_text(thetext) - + svg.append('>%s</tspan>\n' % thetext) curr_x = new_x + xadvance @@ -407,7 +407,7 @@ for x, y, width, height in svg_rects: svg.append('<rect x="%s" y="%s" width="%s" height="%s" fill="black" stroke="none" />' % (x, -y + height, width, height)) svg.append("</g>") - + self._svgwriter.write (''.join(svg)) self.close_group("mathtext") Modified: trunk/matplotlib/lib/matplotlib/font_manager.py =================================================================== --- trunk/matplotlib/lib/matplotlib/font_manager.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/font_manager.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -2,7 +2,7 @@ A module for finding, managing, and using fonts across-platforms. This module provides a single FontManager that can be shared across -backends and platforms. The findfont() method returns the best +backends and platforms. The findfont() function returns the best TrueType (TTF) font file in the local or system font path that matches the specified FontProperties. The FontManager also handles Adobe Font Metrics (AFM) font files for use by the PostScript backend. @@ -231,10 +231,10 @@ if sys.platform == 'darwin': for f in OSXInstalledFonts(): fontfiles[f] = 1 - + for f in get_fontconfig_fonts(fontext): fontfiles[f] = 1 - + elif isinstance(fontpaths, (str, unicode)): fontpaths = [fontpaths] @@ -654,7 +654,7 @@ def get_name(self): """Return the name of the font that best matches the font properties.""" - return ft2font.FT2Font(str(fontManager.findfont(self))).family_name + return ft2font.FT2Font(str(findfont(self))).family_name def get_style(self): """Return the font style. Values are: normal, italic or oblique.""" @@ -849,42 +849,23 @@ # use anything self.defaultFont = self.ttffiles[0] - cache_message = \ -"""Saving TTF font cache for non-PS backends to %s. -Delete this file to have matplotlib rebuild the cache.""" + self.ttfdict = createFontDict(self.ttffiles) - oldcache = os.path.join(get_home(), 'ttffont.cache') - ttfcache = os.path.join(get_configdir(), 'ttffont.cache') - if os.path.exists(oldcache): - print >> sys.stderr, 'Moving old ttfcache location "%s" to new location "%s"'%(oldcache, ttfcache) - shutil.move(oldcache, ttfcache) - - def rebuild(): - self.ttfdict = createFontDict(self.ttffiles) - pickle_dump(self.ttfdict, ttfcache) - verbose.report(cache_message % ttfcache) - - try: - self.ttfdict = pickle_load(ttfcache) - except: - rebuild() + if rcParams['pdf.use14corefonts']: + # Load only the 14 PDF core fonts. These fonts do not need to be + # embedded; every PDF viewing application is required to have them: + # Helvetica, Helvetica-Bold, Helvetica-Oblique, Helvetica-BoldOblique, + # Courier, Courier-Bold, Courier-Oblique, Courier-BoldOblique, + # Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic, Symbol, + # ZapfDingbats. + afmpath = os.path.join(rcParams['datapath'],'fonts','pdfcorefonts') + afmfiles = findSystemFonts(afmpath, fontext='afm') + self.afmdict = createFontDict(afmfiles, fontext='afm') else: - # verify all the cached fnames still exist; if not rebuild - for fname in ttfdict_to_fnames(self.ttfdict): - if not os.path.exists(fname): - rebuild() - break - verbose.report('loaded ttfcache file %s'%ttfcache) + self.afmfiles = findSystemFonts(paths, fontext='afm') + \ + findSystemFonts(fontext='afm') + self.afmdict = createFontDict(self.afmfiles, fontext='afm') - #self.ttfdict = createFontDict(self.ttffiles) - - # Load AFM fonts for PostScript - # Only load file names at this stage, the font dictionary will be - # created when needed. - self.afmfiles = findSystemFonts(paths, fontext='afm') + \ - findSystemFonts(fontext='afm') - self.afmdict = {} - def get_default_weight(self): "Return the default font weight." return self.__default_weight @@ -930,8 +911,6 @@ return fname if fontext == 'afm': - if len(self.afmdict) == 0: - self.afmdict = self._get_afm_font_dict() fontdict = self.afmdict else: fontdict = self.ttfdict @@ -1009,7 +988,7 @@ return fname font_family_aliases = ['serif', 'sans-serif', 'cursive', 'fantasy', 'monospace'] - + for name in prop.get_family(): if name in font_family_aliases: for name2 in rcParams['font.' + name]: @@ -1028,37 +1007,29 @@ return self.defaultFont return fname - def _get_afm_font_dict(self): - cache_message = "Saving AFM font cache for PS and PDF backends to %s.\n" \ - "Delete this file to have matplotlib rebuild the cache." - if rcParams['pdf.use14corefonts']: - # Load only the 14 PDF core fonts. These fonts do not need to be - # embedded; every PDF viewing application is required to have them: - # Helvetica, Helvetica-Bold, Helvetica-Oblique, Helvetica-BoldOblique, - # Courier, Courier-Bold, Courier-Oblique, Courier-BoldOblique, - # Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic, Symbol, - # ZapfDingbats. - afmcache = os.path.join(get_configdir(), 'pdfcorefont.cache') - try: - fontdict = pickle_load(afmcache) - except: - afmpath = os.path.join(rcParams['datapath'],'fonts','pdfcorefonts') - afmfiles = findSystemFonts(afmpath, fontext='afm') - fontdict = createFontDict(afmfiles, fontext='afm') - pickle_dump(fontdict, afmcache) - verbose.report(cache_message % afmcache) - else: - # Load all available AFM fonts - afmcache = os.path.join(get_configdir(), '.afmfont.cache') - try: - fontdict = pickle_load(afmcache) - except: - fontdict = createFontDict(self.afmfiles, fontext='afm') - pickle_dump(fontdict, afmcache) - verbose.report(cache_message % afmcache) +_fmcache = os.path.join(get_configdir(), 'fontManager.cache') - return fontdict +fontManager = None +def _rebuild(): + global fontManager + fontManager = FontManager() + pickle_dump(fontManager, _fmcache) + verbose.report("generated new fontManager") -fontManager = FontManager() +try: + fontManager = pickle_load(_fmcache) + verbose.report("Using fontManager instance from %s" % _fmcache) +except: + _rebuild() + +def findfont(prop, **kw): + global fontManager + font = fontManager.findfont(prop, **kw) + if not os.path.exists(font): + verbose.report("%s returned by pickled fontManager does not exist" % font) + _rebuild() + font = fontManager.findfont(prop, **kw) + return font + Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-13 15:19:11 UTC (rev 3706) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-14 07:07:45 UTC (rev 3707) @@ -71,7 +71,7 @@ Allowed TeX symbols: [MGDTODO: This list is no longer exhaustive and needs to be updated] - + \/ \Delta \Downarrow \Gamma \Im \LEFTangle \LEFTbrace \LEFTbracket \LEFTparen \Lambda \Leftarrow \Leftbrace \Leftbracket \Leftparen \Leftrightarrow \Omega \P \Phi \Pi \Psi \RIGHTangle \RIGHTbrace @@ -120,7 +120,7 @@ The *Unicode* classes were incomplete when I found them, and have not been refactored to support intermingling of regular text and math text yet. They are most likely broken. -- Michael Droettboom, July 2007 - + Author : John Hunter <jdh...@ac...> Michael Droettboom <md...@st...> (rewrite based on TeX box layout algorithms) @@ -149,14 +149,14 @@ from matplotlib.cbook import enumerate, iterable, Bunch, get_realpath_and_stat, \ is_string_like from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_DEFAULT, LOAD_NO_HINTING -from matplotlib.font_manager import fontManager, FontProperties +from matplotlib.font_manager import findfont, FontProperties from matplotlib._mathtext_data import latex_to_bakoma, \ latex_to_standard, tex2uni, type12uni, tex2type1, uni2type1 from matplotlib import get_data_path, rcParams #################### - + # a character over another character charOverChars = { # The first 2 entires in the tuple are (font, char, sizescale) for @@ -240,7 +240,7 @@ def get_hinting_type(self): return LOAD_NO_HINTING - + class MathtextBackendAgg(MathtextBackend): def set_canvas_size(self, w, h): MathtextBackend.set_canvas_size(self, w, h) @@ -263,17 +263,17 @@ def get_hinting_type(self): return LOAD_DEFAULT - + class MathtextBackendPs(MathtextBackend): def __init__(self): self.pswriter = StringIO() - + def render_glyph(self, ox, oy, info): oy = self.height - oy + info.offset postscript_name = info.postscript_name fontsize = info.fontsize symbol_name = info.symbol_name - + ps = """/%(postscript_name)s findfont %(fontsize)s scalefont setfont @@ -291,12 +291,12 @@ self.height, self.pswriter, self.fonts_object.get_used_characters()) - + class MathtextBackendPdf(MathtextBackend): def __init__(self): self.glyphs = [] self.rects = [] - + def render_glyph(self, ox, oy, info): filename = info.font.fname oy = self.height - oy + info.offset @@ -318,7 +318,7 @@ def __init__(self): self.svg_glyphs = [] self.svg_rects = [] - + def render_glyph(self, ox, oy, info): oy = self.height - oy + info.offset thetext = unichr(info.num) @@ -341,7 +341,7 @@ def __init__(self): self.glyphs = [] self.rects = [] - + def render_glyph(self, ox, oy, info): oy = oy - info.offset - self.height thetext = unichr(info.num) @@ -357,7 +357,7 @@ self.height, self.glyphs, self.rects) - + class Fonts(object): """ An abstract base class for fonts that want to render mathtext @@ -378,7 +378,7 @@ # Make these classes doubly-linked self.mathtext_backend.fonts_object = self self.used_characters = {} - + def get_kern(self, font1, sym1, fontsize1, font2, sym2, fontsize2, dpi): """ @@ -389,7 +389,7 @@ symX: a symbol in raw TeX form. e.g. '1', 'x' or '\sigma' fontsizeX: the fontsize in points dpi: the current dots-per-inch - + sym is a single symbol(alphanum, punct) or a special symbol like \sigma. @@ -435,7 +435,7 @@ def get_underline_thickness(self, font, fontsize, dpi): raise NotImplementedError() - + def get_used_characters(self): return self.used_characters @@ -446,7 +446,7 @@ """Override if your font provides multiple sizes of the same symbol.""" return [(fontname, sym)] - + class TruetypeFonts(Fonts): """ A generic base class for all font setups that use Truetype fonts @@ -467,17 +467,17 @@ def __repr__(self): return repr(self.font) - + def __init__(self, default_font_prop, mathtext_backend): Fonts.__init__(self, default_font_prop, mathtext_backend) self.glyphd = {} self.fonts = {} - filename = fontManager.findfont(default_font_prop) + filename = findfont(default_font_prop) default_font = self.CachedFont(FT2Font(str(filename))) - + self.fonts['default'] = default_font - + def _get_font(self, font): """Looks up a CachedFont with its charmap and inverse charmap. font may be a TeX font name (cal, rm, it etc.), or postscript name.""" @@ -500,7 +500,7 @@ def _get_offset(self, cached_font, glyph, fontsize, dpi): return 0. - + def _get_info (self, fontname, sym, fontsize, dpi, mark_as_used=True): 'load the cmfont, metrics and glyph with caching' key = fontname, sym, fontsize, dpi @@ -567,7 +567,7 @@ font = info1.font return font.get_kerning(info1.num, info2.num, KERNING_DEFAULT) / 64.0 return 0.0 - + class BakomaFonts(TruetypeFonts): """ Use the Bakoma true type fonts for rendering @@ -581,7 +581,7 @@ 'ex' : 'cmex10' } fontmap = {} - + def __init__(self, *args, **kwargs): TruetypeFonts.__init__(self, *args, **kwargs) if not len(self.fontmap): @@ -589,14 +589,14 @@ fullpath = os.path.join(self.basepath, val + ".ttf") self.fontmap[key] = fullpath self.fontmap[val] = fullpath - + def _get_offset(self, cached_font, glyph, fontsize, dpi): if cached_font.font.postscript_name == 'Cmex10': return glyph.height/64.0/2.0 + 256.0/64.0 * dpi/72.0 return 0. _slanted_symbols = Set(r"\int \oint".split()) - + def _get_glyph(self, fontname, sym, fontsize): if fontname in self.fontmap and latex_to_bakoma.has_key(sym): basename, num = latex_to_bakoma[sym] @@ -664,19 +664,19 @@ ('\leftbracket', '['), ('\rightbracket', ']')]: _size_alternatives[alias] = _size_alternatives[target] - + def get_sized_alternatives_for_symbol(self, fontname, sym): alternatives = self._size_alternatives.get(sym) if alternatives: return alternatives return [(fontname, sym)] - + class UnicodeFonts(TruetypeFonts): """An abstract base class for handling Unicode fonts. """ fontmap = {} - + def __init__(self, *args, **kwargs): # This must come first so the backend's owner is set correctly if rcParams['mathtext.fallback_to_cm']: @@ -689,15 +689,15 @@ setting = rcParams['mathtext.' + texfont] family, weight, style = setting prop = FontProperties(family=family, weight=weight, style=style) - font = fontManager.findfont(prop) + font = findfont(prop) self.fontmap[texfont] = font - + def _get_offset(self, cached_font, glyph, fontsize, dpi): return 0. def _get_glyph(self, fontname, sym, fontsize): found_symbol = False - + try: uniindex = get_unicode_index(sym) found_symbol = True @@ -743,7 +743,7 @@ uniindex = 0xA4 # currency character, for lack of anything better glyphindex = cached_font.charmap[uniindex] slanted = False - + symbol_name = cached_font.font.get_glyph_name(glyphindex) return cached_font, uniindex, symbol_name, fontsize, slanted @@ -752,7 +752,7 @@ TruetypeFonts.set_canvas_size(self, w, h) if self.cm_fallback: self.cm_fallback.set_canvas_size(w, h) - + def get_used_characters(self): used_characters = dict(self.used_characters) if self.cm_fallback: @@ -766,7 +766,7 @@ if self.cm_fallback: fonts.extend(self.cm_fallback.get_fonts()) return list(set(fonts)) - + class StandardPsFonts(Fonts): """ Use the standard postscript fonts for rendering to backend_ps @@ -778,7 +778,7 @@ fontmap = { 'cal' : 'pzcmi8a', # Zapf Chancery 'rm' : 'pncr8a', # New Century Schoolbook - 'tt' : 'pcrr8a', # Courier + 'tt' : 'pcrr8a', # Courier 'it' : 'pncri8a', # New Century Schoolbook Italic 'sf' : 'phvr8a', # Helvetica 'bf' : 'pncb8a', # New Century Schoolbook Bold @@ -790,13 +790,13 @@ self.glyphd = {} self.fonts = {} - filename = fontManager.findfont(default_font_prop, fontext='afm') + filename = findfont(default_font_prop, fontext='afm') default_font = AFM(file(filename, 'r')) default_font.fname = filename - + self.fonts['default'] = default_font self.pswriter = StringIO() - + def _get_font(self, font): if font in self.fontmap: basename = self.fontmap[font] @@ -814,7 +814,7 @@ def get_fonts(self): return list(set(self.fonts.values())) - + def _get_info (self, fontname, sym, fontsize, dpi): 'load the cmfont, metrics and glyph with caching' key = fontname, sym, fontsize, dpi @@ -831,7 +831,7 @@ fontname = 'rm' found_symbol = False - + if latex_to_standard.has_key(sym): fontname, num = latex_to_standard[sym] glyph = chr(num) @@ -845,7 +845,7 @@ MathTextWarning) slanted = (fontname == 'it') - font = self._get_font(fontname) + font = self._get_font(fontname) if found_symbol: try: @@ -860,7 +860,7 @@ glyph = sym = '?' num = ord(glyph) symbol_name = font.get_name_char(glyph) - + offset = 0 scale = 0.001 * fontsize @@ -890,7 +890,7 @@ glyph = glyph, offset = offset ) - + return self.glyphd[key] def get_kern(self, font1, sym1, fontsize1, @@ -910,7 +910,7 @@ def get_underline_thickness(self, font, fontsize, dpi): cached_font = self._get_font(font) return cached_font.get_underline_thickness() * 0.001 * fontsize - + ############################################################################## # TeX-LIKE BOX MODEL @@ -951,17 +951,17 @@ SUB1 = 0.0 # Percentage of x-height that superscripts are offset relative to the subscript DELTA = 0.18 - + class MathTextWarning(Warning): pass - + class Node(object): """A node in the TeX box model @133 """ def __init__(self): self.size = 0 - + def __repr__(self): return self.__internal_repr__() @@ -980,7 +980,7 @@ """Grows one level larger. There is no limit to how big something can get.""" self.size -= 1 - + def render(self, x, y): pass @@ -1005,7 +1005,7 @@ self.width *= GROW_FACTOR self.height *= GROW_FACTOR self.depth *= GROW_FACTOR - + def render(self, x1, y1, x2, y2): pass @@ -1016,7 +1016,7 @@ class Hbox(Box): def __init__(self, width): Box.__init__(self, width, 0., 0.) - + class Char(Node): """Represents a single character. Unlike TeX, the font information and metrics are stored with each Char to make it @@ -1038,7 +1038,7 @@ # The real width, height and depth will be set during the # pack phase, after we know the real fontsize self._update_metrics() - + def __internal_repr__(self): return '`%s`' % self.c @@ -1054,7 +1054,7 @@ def is_slanted(self): return self._metrics.slanted - + def get_kerning(self, next): """Return the amount of kerning between this and the given character. Called when characters are strung together into @@ -1067,7 +1067,7 @@ next.font, next.c, next.fontsize, self.dpi) return advance + kern - + def render(self, x, y): """Render the character to the canvas""" self.font_output.render_glyph( @@ -1088,7 +1088,7 @@ self.width *= GROW_FACTOR self.height *= GROW_FACTOR self.depth *= GROW_FACTOR - + class Accent(Char): """The font metrics need to be dealt with differently for accents, since they are already offset correctly from the baseline in TrueType fonts.""" @@ -1102,17 +1102,17 @@ def shrink(self): Char.shrink(self) self._update_metrics() - + def grow(self): Char.grow(self) self._update_metrics() - + def render(self, x, y): """Render the character to the canvas""" self.font_output.render_glyph( x - self._metrics.xmin, y + self._metrics.ymin, self.font, self.c, self.fontsize, self.dpi) - + class List(Box): """A list of nodes (either horizontal or vertical). @135""" @@ -1170,7 +1170,7 @@ Box.grow(self) self.shift_amount *= GROW_FACTOR self.glue_set *= GROW_FACTOR - + class Hlist(List): """A horizontal list of boxes. @135""" @@ -1260,7 +1260,7 @@ self._set_glue(x, 1, total_stretch, "Overfull") else: self._set_glue(x, -1, total_shrink, "Underfull") - + class Vlist(List): """A vertical list of boxes. @137""" @@ -1308,7 +1308,7 @@ d = 0. elif isinstance(p, Char): raise RuntimeError("Internal mathtext error: Char node found in Vlist.") - + self.width = w if d > l: x += d - l @@ -1331,7 +1331,7 @@ self._set_glue(x, 1, total_stretch, "Overfull") else: self._set_glue(x, -1, total_shrink, "Underfull") - + class Rule(Box): """A Rule node stands for a solid black rectangle; it has width, depth, and height fields just as in an Hlist. However, if any of these @@ -1343,10 +1343,10 @@ def __init__(self, width, height, depth, state): Box.__init__(self, width, height, depth) self.font_output = state.font_output - + def render(self, x, y, w, h): self.font_output.render_rect_filled(x, y, x + w, y + h) - + class Hrule(Rule): """Convenience class to create a horizontal rule.""" def __init__(self, state): @@ -1361,7 +1361,7 @@ thickness = state.font_output.get_underline_thickness( state.font, state.fontsize, state.dpi) Rule.__init__(self, thickness, inf, inf, state) - + class Glue(Node): """Most of the information in this object is stored in the underlying GlueSpec class, which is shared between multiple glue objects. (This @@ -1393,7 +1393,7 @@ if self.glue_spec.width != 0.: self.glue_spec = self.glue_spec.copy() self.glue_spec.width *= GROW_FACTOR - + class GlueSpec(object): """@150, @151""" def __init__(self, width=0., stretch=0., stretch_order=0, shrink=0., shrink_order=0): @@ -1410,11 +1410,11 @@ self.stretch_order, self.shrink, self.shrink_order) - + def factory(cls, glue_type): return cls._types[glue_type] factory = classmethod(factory) - + GlueSpec._types = { 'fil': GlueSpec(0., 1., 1, 0., 0), 'fill': GlueSpec(0., 1., 2, 0., 0), @@ -1451,24 +1451,24 @@ class NegFilll(Glue): def __init__(self): Glue.__init__(self, 'neg_filll') - + class SsGlue(Glue): def __init__(self): Glue.__init__(self, 'ss') - + class HCentered(Hlist): """A convenience class to create an Hlist whose contents are centered within its enclosing box.""" def __init__(self, elements): Hlist.__init__(self, [SsGlue()] + elements + [SsGlue()], do_kern=False) - + class VCentered(Hlist): """A convenience class to create an Vlist whose contents are centered within its enclosing box.""" def __init__(self, elements): Vlist.__init__(self, [SsGlue()] + elements + [SsGlue()]) - + class Kern(Node): """A Kern node has a width field to specify a (normally negative) amount of spacing. This spacing correction appears in horizontal lists @@ -1483,7 +1483,7 @@ def __repr__(self): return "k%.02f" % self.width - + def shrink(self): Node.shrink(self) if self.size < NUM_SIZE_LEVELS: @@ -1492,7 +1492,7 @@ def grow(self): Node.grow(self) self.width *= GROW_FACTOR - + class SubSuperCluster(Hlist): """This class is a sort of hack to get around that fact that this code doesn't parse to an mlist and then an hlist, but goes directly @@ -1526,7 +1526,7 @@ factor = target_total / (char.height + char.depth) state.fontsize *= factor char = Char(sym, state) - + shift = (depth - char.depth) Hlist.__init__(self, [char]) self.shift_amount = shift @@ -1551,9 +1551,9 @@ factor = width / char.width state.fontsize *= factor char = char_class(sym, state) - + Hlist.__init__(self, [char]) - + class Ship(object): """Once the boxes have been set up, this sends them to output. Since boxes can be inside of boxes inside of boxes, the main @@ -1578,7 +1578,7 @@ return 1000000000. return value clamp = staticmethod(clamp) - + def hlist_out(self, box): cur_g = 0 cur_glue = 0. @@ -1697,7 +1697,7 @@ elif isinstance(p, Char): raise RuntimeError("Internal mathtext error: Char node found in vlist") self.cur_s -= 1 - + ship = Ship() ############################################################################## @@ -1760,7 +1760,7 @@ ) _dropsub_symbols = Set(r'''\int \oint'''.split()) - + def __init__(self): # All forward declarations are here font = Forward().setParseAction(self.font).setName("font") @@ -1873,7 +1873,7 @@ ).setParseAction(self.sqrt).setName("sqrt") placeable <<(accent - ^ function + ^ function ^ symbol ^ rightBracket ^ group @@ -1888,7 +1888,7 @@ subsuperop =(Literal("_") | Literal("^") - ) + ) subsuper << Group( ( Optional(placeable) @@ -1911,9 +1911,9 @@ autoDelim ^ OneOrMore(simple)) + Suppress(Literal(r"\right")) - + (rightDelim | ambiDelim) + + (rightDelim | ambiDelim) ) - + math = OneOrMore( autoDelim | simple @@ -1941,7 +1941,7 @@ self._expr = None self._state_stack = None self._em_width_cache = {} - + def parse(self, s, fonts_object, fontsize, dpi): self._state_stack = [self.State(fonts_object, 'default', fontsize, dpi)] self._expression.parseString(s) @@ -1964,7 +1964,7 @@ self.font, self.fontsize, self.dpi) - + def get_state(self): return self._state_stack[-1] @@ -1973,11 +1973,11 @@ def push_state(self): self._state_stack.append(self.get_state().copy()) - + def finish(self, s, loc, toks): self._expr = Hlist(toks) return [self._expr] - + def math(self, s, loc, toks): #~ print "math", toks hlist = Hlist(toks) @@ -2056,7 +2056,7 @@ } _wide_accents = Set(r"\widehat \widetilde".split()) - + def accent(self, s, loc, toks): assert(len(toks)==1) state = self.get_state() @@ -2087,14 +2087,14 @@ self.pop_state() hlist.function_name = toks[0] return hlist - + def start_group(self, s, loc, toks): self.push_state() # Deal with LaTeX-style font tokens if len(toks): self.get_state().font = toks[0][4:] return [] - + def group(self, s, loc, toks): grp = Hlist(toks[0]) return [grp] @@ -2102,7 +2102,7 @@ def end_group(self, s, loc, toks): self.pop_state() return [] - + def font(self, s, loc, toks): assert(len(toks)==1) name = toks[0] @@ -2125,7 +2125,7 @@ if isinstance(nucleus, Char): return nucleus.is_slanted() return False - + def subsuperscript(self, s, loc, toks): assert(len(toks)==1) # print 'subsuperscript', toks @@ -2133,7 +2133,7 @@ nucleus = None sub = None super = None - + if len(toks[0]) == 1: return toks[0].asList() elif len(toks[0]) == 2: @@ -2164,13 +2164,13 @@ sub = next2 else: raise ParseFatalException("Subscript/superscript sequence is too long.") - + state = self.get_state() rule_thickness = state.font_output.get_underline_thickness( state.font, state.fontsize, state.dpi) xHeight = state.font_output.get_xheight( state.font, state.fontsize, state.dpi) - + if self.is_overunder(nucleus): vlist = [] shift = 0. @@ -2181,7 +2181,7 @@ if sub is not None: sub.shrink() width = max(width, sub.width) - + if super is not None: hlist = HCentered([super]) hlist.hpack(width, 'exactly') @@ -2248,7 +2248,7 @@ state = self.get_state() thickness = state.font_output.get_underline_thickness( state.font, state.fontsize, state.dpi) - + num, den = toks[0] num.shrink() den.shrink() @@ -2316,14 +2316,14 @@ # The value of 0.6 is a hard-coded hack ;) root_vlist = Vlist([Hlist([root])]) root_vlist.shift_amount = -height * 0.6 - + hlist = Hlist([root_vlist, # Root # Negative kerning to put root over tick - Kern(-check.width * 0.5), + Kern(-check.width * 0.5), check, # Check rightside]) # Body return [hlist] - + def auto_sized_delimiter(self, s, loc, toks): #~ print "auto_sized_delimiter", toks front, middle, back = toks @@ -2339,12 +2339,12 @@ parts.append(AutoHeightChar(back, height, depth, state)) hlist = Hlist(parts) return hlist - + #### ############################################################################## # MAIN - + class math_parse_s_ft2font_common: """ Parse the math expression s, return the (bbox, fonts) tuple needed @@ -2367,7 +2367,7 @@ 'SVG' : MathtextBackendSvg, 'Cairo' : MathtextBackendCairo } - + def __init__(self, output): self.output = output self.cache = {} @@ -2404,7 +2404,7 @@ font_output.mathtext_backend.fonts_object = None return result - + math_parse_s_ft2font = math_parse_s_ft2font_common('Agg') math_parse_s_ft2font_svg = math_parse_s_ft2font_common('SVG') math_parse_s_ps = math_parse_s_ft2font_common('PS') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ds...@us...> - 2007-08-14 14:14:23
|
Revision: 3709 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3709&view=rev Author: dsdale Date: 2007-08-14 07:13:27 -0700 (Tue, 14 Aug 2007) Log Message: ----------- fixed a bug in pyqt4 subplots-adjust Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/__init__.py trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2007-08-14 13:22:56 UTC (rev 3708) +++ trunk/matplotlib/CHANGELOG 2007-08-14 14:13:27 UTC (rev 3709) @@ -1,3 +1,6 @@ +2007-08-14 Fixed a bug in pyqt4 subplots-adjust. Thanks to + Xavier Gnata for the report and suggested fix - DSD + 2007-08-13 Use pickle to cache entire fontManager; change to using font_manager module-level function findfont wrapper for the fontManager.findfont method - EF Modified: trunk/matplotlib/lib/matplotlib/__init__.py =================================================================== --- trunk/matplotlib/lib/matplotlib/__init__.py 2007-08-14 13:22:56 UTC (rev 3708) +++ trunk/matplotlib/lib/matplotlib/__init__.py 2007-08-14 14:13:27 UTC (rev 3709) @@ -709,11 +709,10 @@ if NEWCONFIG: #print "importing from reorganized config system!" - from config import rcParams, rcdefaults try: - from config import mplConfig, save_config + from config import rcParams, rcdefaults, mplConfig, save_config except: - pass + from config import rcParams, rcdefaults def use(arg): """ Modified: trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py 2007-08-14 13:22:56 UTC (rev 3708) +++ trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py 2007-08-14 14:13:27 UTC (rev 3709) @@ -405,13 +405,17 @@ self.sliderhspace = QtGui.QSlider(QtCore.Qt.Vertical) # constraints - QtCore.QObject.connect( self.sliderleft, QtCore.SIGNAL( "valueChanged(int)" ), + QtCore.QObject.connect( self.sliderleft, + QtCore.SIGNAL( "valueChanged(int)" ), self.sliderright.setMinimum ) - QtCore.QObject.connect( self.sliderright, QtCore.SIGNAL( "valueChanged(int)" ), + QtCore.QObject.connect( self.sliderright, + QtCore.SIGNAL( "valueChanged(int)" ), self.sliderleft.setMaximum ) - QtCore.QObject.connect( self.sliderbottom, QtCore.SIGNAL( "valueChanged(int)" ), + QtCore.QObject.connect( self.sliderbottom, + QtCore.SIGNAL( "valueChanged(int)" ), self.slidertop.setMinimum ) - QtCore.QObject.connect( self.slidertop, QtCore.SIGNAL( "valueChanged(int)" ), + QtCore.QObject.connect( self.slidertop, + QtCore.SIGNAL( "valueChanged(int)" ), self.sliderbottom.setMaximum ) sliders = (self.sliderleft, self.sliderbottom, self.sliderright, @@ -464,38 +468,56 @@ self.setLayout(layout) self.sliderleft.setSliderPosition(int(targetfig.subplotpars.left*1000)) - self.sliderbottom.setSliderPosition(int(targetfig.subplotpars.bottom*1000)) - self.sliderright.setSliderPosition(int(targetfig.subplotpars.right*1000)) + self.sliderbottom.setSliderPosition(\ + int(targetfig.subplotpars.bottom*1000)) + self.sliderright.setSliderPosition(\ + int(targetfig.subplotpars.right*1000)) self.slidertop.setSliderPosition(int(targetfig.subplotpars.top*1000)) - self.sliderwspace.setSliderPosition(int(targetfig.subplotpars.wspace*1000)) - self.sliderhspace.setSliderPosition(int(targetfig.subplotpars.hspace*1000)) + self.sliderwspace.setSliderPosition(\ + int(targetfig.subplotpars.wspace*1000)) + self.sliderhspace.setSliderPosition(\ + int(targetfig.subplotpars.hspace*1000)) - QtCore.QObject.connect( self.sliderleft, QtCore.SIGNAL( "valueChanged(int)" ), + QtCore.QObject.connect( self.sliderleft, + QtCore.SIGNAL( "valueChanged(int)" ), self.funcleft ) - QtCore.QObject.connect( self.sliderbottom, QtCore.SIGNAL( "valueChanged(int)" ), + QtCore.QObject.connect( self.sliderbottom, + QtCore.SIGNAL( "valueChanged(int)" ), self.funcbottom ) - QtCore.QObject.connect( self.sliderright, QtCore.SIGNAL( "valueChanged(int)" ), + QtCore.QObject.connect( self.sliderright, + QtCore.SIGNAL( "valueChanged(int)" ), self.funcright ) - QtCore.QObject.connect( self.slidertop, QtCore.SIGNAL( "valueChanged(int)" ), + QtCore.QObject.connect( self.slidertop, + QtCore.SIGNAL( "valueChanged(int)" ), self.functop ) - QtCore.QObject.connect( self.sliderwspace, QtCore.SIGNAL( "valueChanged(int)" ), + QtCore.QObject.connect( self.sliderwspace, + QtCore.SIGNAL( "valueChanged(int)" ), self.funcwspace ) - QtCore.QObject.connect( self.sliderhspace, QtCore.SIGNAL( "valueChanged(int)" ), + QtCore.QObject.connect( self.sliderhspace, + QtCore.SIGNAL( "valueChanged(int)" ), self.funchspace ) def funcleft(self, val): + if val == self.sliderright.value(): + val -= 1 self.targetfig.subplots_adjust(left=val/1000.) if self.drawon: self.targetfig.canvas.draw() def funcright(self, val): + if val == self.sliderleft.value(): + val += 1 self.targetfig.subplots_adjust(right=val/1000.) if self.drawon: self.targetfig.canvas.draw() def funcbottom(self, val): + if val == self.slidertop.value(): + val -= 1 self.targetfig.subplots_adjust(bottom=val/1000.) if self.drawon: self.targetfig.canvas.draw() def functop(self, val): + if val == self.sliderbottom.value(): + val += 1 self.targetfig.subplots_adjust(top=val/1000.) if self.drawon: self.targetfig.canvas.draw() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ds...@us...> - 2007-08-16 12:53:17
|
Revision: 3710 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3710&view=rev Author: dsdale Date: 2007-08-16 05:53:13 -0700 (Thu, 16 Aug 2007) Log Message: ----------- added set_extent method to AxesImage Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/examples/embedding_in_qt4.py trunk/matplotlib/lib/matplotlib/image.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2007-08-14 14:13:27 UTC (rev 3709) +++ trunk/matplotlib/CHANGELOG 2007-08-16 12:53:13 UTC (rev 3710) @@ -1,3 +1,6 @@ +2007-08-16 Added a set_extent method to AxesImage, allow data extent + to be modified after initial call to imshow - DSD + 2007-08-14 Fixed a bug in pyqt4 subplots-adjust. Thanks to Xavier Gnata for the report and suggested fix - DSD Modified: trunk/matplotlib/examples/embedding_in_qt4.py =================================================================== --- trunk/matplotlib/examples/embedding_in_qt4.py 2007-08-14 14:13:27 UTC (rev 3709) +++ trunk/matplotlib/examples/embedding_in_qt4.py 2007-08-16 12:53:13 UTC (rev 3710) @@ -64,11 +64,13 @@ def compute_initial_figure(self): self.axes.plot([0, 1, 2, 3], [1, 2, 0, 4], 'r') + self.axes.set_yscale('log') def update_figure(self): # Build a list of 4 random integers between 0 and 10 (both inclusive) l = [ random.randint(0, 10) for i in xrange(4) ] + l[l<=0]=1 self.axes.plot([0, 1, 2, 3], l, 'r') self.draw() Modified: trunk/matplotlib/lib/matplotlib/image.py =================================================================== --- trunk/matplotlib/lib/matplotlib/image.py 2007-08-14 14:13:27 UTC (rev 3709) +++ trunk/matplotlib/lib/matplotlib/image.py 2007-08-16 12:53:13 UTC (rev 3710) @@ -236,6 +236,18 @@ # by mistake. self.set_data(A) + + def set_extent(self, extent): + """extent is data axes (left, right, bottom, top) for making image plots + """ + self._extent = extent + + xmin, xmax, ymin, ymax = extent + corners = (xmin, ymin), (xmax, ymax) + self.axes.update_datalim(corners) + if self.axes._autoscaleon: + self.axes.set_xlim((xmin, xmax)) + self.axes.set_ylim((ymin, ymax)) def get_interpolation(self): """ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-20 16:11:35
|
Revision: 3719 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3719&view=rev Author: mdboom Date: 2007-08-20 09:11:29 -0700 (Mon, 20 Aug 2007) Log Message: ----------- Change mathtext.* rcParams so they accept a string which is a set of arguments to the FontProperties constructor. This has been added to both the classic and traits based configuration frameworks. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/config/mplconfig.py trunk/matplotlib/lib/matplotlib/config/mpltraits.py trunk/matplotlib/lib/matplotlib/config/rcsetup.py trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc trunk/matplotlib/lib/matplotlib/rcsetup.py trunk/matplotlib/matplotlibrc.template Modified: trunk/matplotlib/lib/matplotlib/config/mplconfig.py =================================================================== --- trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2007-08-20 12:47:45 UTC (rev 3718) +++ trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2007-08-20 16:11:29 UTC (rev 3719) @@ -161,12 +161,12 @@ dvipnghack = T.false class mathtext(TConfig): - cal = T.Trait('cursive', 'cursive', 'normal', 'normal') - rm = T.Trait('serif', 'serif', 'normal', 'normal') - tt = T.Trait('monospace', 'monospace', 'normal', 'normal') - it = T.Trait('serif', 'serif', 'normal', 'italic') - bf = T.Trait('serif', 'serif', 'bold', 'normal') - sf = T.Trait('sans-serif', 'sans-serif', 'normal', 'normal') + cal = T.Trait("['cursive']", mplT.FontPropertiesHandler()) + rm = T.Trait("['serif']", mplT.FontPropertiesHandler()) + tt = T.Trait("['monospace']", mplT.FontPropertiesHandler()) + it = T.Trait("['serif'], style='oblique'", mplT.FontPropertiesHandler()) + bf = T.Trait("['serif'], weight='bold'", mplT.FontPropertiesHandler()) + sf = T.Trait("['sans-serif']", mplT.FontPropertiesHandler()) use_cm = T.true fallback_to_cm = T.true Modified: trunk/matplotlib/lib/matplotlib/config/mpltraits.py =================================================================== --- trunk/matplotlib/lib/matplotlib/config/mpltraits.py 2007-08-20 12:47:45 UTC (rev 3718) +++ trunk/matplotlib/lib/matplotlib/config/mpltraits.py 2007-08-20 16:11:29 UTC (rev 3719) @@ -144,3 +144,65 @@ 'hsv', 'hsv_r', 'jet', 'jet_r', 'pink', 'pink_r', 'prism', 'prism_r', 'spectral', 'spectral_r', 'spring', 'spring_r', 'summer', 'summer_r', 'winter', 'winter_r'] + +class FontPropertiesHandler(T.TraitHandler): + class FontPropertiesProxy: + # In order to build a FontProperties object, various rcParams must + # already be known in order to set default values. That means a + # FontProperties object can not be created from a config file, + # since it depends on other values in the same config file. This + # proxy class is used as a temporary storage area for the settings + # in the config file, and the full FontProperties class is created + # only when the class is first used. It is defined here rather than + # in font_manager.py to avoid a cyclical import. + def __init__(self, + family = None, + style = None, + variant= None, + weight = None, + stretch= None, + size = None, + fname = None, # if this is set, it's a hardcoded filename to use + ): + self.__family = family + self.__style = style + self.__variant = variant + self.__weight = weight + self.__stretch = stretch + self.__size = size + self.__fname = fname + + self.__child = None + + def __get_child(self): + if self.__child is None: + from matplotlib.font_manager import FontProperties + self.__child = FontProperties( + family = self.__family, + style = self.__style, + variant = self.__variant, + weight = self.__weight, + stretch = self.__stretch, + size = self.__size, + fname = self.__fname) + return self.__child + + def __getattr__(self, attr): + return getattr(self.__get_child(), attr) + + def validate(self, object, name, value): + from matplotlib.font_manager import FontProperties + if isinstance(value, FontProperties): + return value + if is_string_like(value): + try: + proxy = eval("FontProperties(%s)" % value, + {}, {'FontProperties': self.FontPropertiesProxy}) + except: + pass + else: + return proxy + self.error(object, name, value) + + def info(self): + return 'Represents a set of font properties. Must be a FontProperties object or a string containing the parameters to the FontProperties constructor.' Modified: trunk/matplotlib/lib/matplotlib/config/rcsetup.py =================================================================== --- trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2007-08-20 12:47:45 UTC (rev 3718) +++ trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2007-08-20 16:11:29 UTC (rev 3719) @@ -198,12 +198,64 @@ except ValueError: raise ValueError('not a valid font size') -def validate_mathtext_font(s): - s = eval(s) - if type(s) in (list, tuple) and len(s) == 3: - return s - raise ValueError('Mathtext font specifier must be a 3-tuple of (family, weight, style)') +class FontPropertiesProxy: + # In order to build a FontProperties object, various rcParams must + # already be known in order to set default values. That means a + # FontProperties object can not be created from a config file, + # since it depends on other values in the same config file. This + # proxy class is used as a temporary storage area for the settings + # in the config file, and the full FontProperties class is created + # only when the class is first used. It is defined here rather than + # in font_manager.py to avoid a cyclical import. + def __init__(self, + family = None, + style = None, + variant= None, + weight = None, + stretch= None, + size = None, + fname = None, # if this is set, it's a hardcoded filename to use + ): + self.__family = family + self.__style = style + self.__variant = variant + self.__weight = weight + self.__stretch = stretch + self.__size = size + self.__fname = fname + + self.__child = None + + def __get_child(self): + if self.__child is None: + from font_manager import FontProperties + self.__child = FontProperties( + family = self.__family, + style = self.__style, + variant = self.__variant, + weight = self.__weight, + stretch = self.__stretch, + size = self.__size, + fname = self.__fname) + return self.__child + + def __getattr__(self, attr): + return getattr(self.__get_child(), attr) +def validate_font_properties(s): + parsed = False + try: + prop = eval(u'FontProperties(%s)' % s, + {}, {'FontProperties': FontPropertiesProxy}) + except: + pass + else: + parsed = isinstance(prop, FontPropertiesProxy) + if not parsed: + raise ValueError( + 'Mathtext font specifier must be a set of arguments to the FontProperty constructor.') + return prop + validate_markup = ValidateInStrings( 'markup', ['plain', 'tex'], @@ -366,12 +418,12 @@ 'text.fontsize' : ['medium', validate_fontsize], 'text.markup' : ['plain', validate_markup], - 'mathtext.cal' : [('cursive', 'normal', 'normal'), validate_mathtext_font], - 'mathtext.rm' : [('serif', 'normal', 'normal'), validate_mathtext_font], - 'mathtext.tt' : [('monospace', 'normal', 'normal'), validate_mathtext_font], - 'mathtext.it' : [('serif', 'normal', 'italic'), validate_mathtext_font], - 'mathtext.bf' : [('serif', 'bold', 'normal'), validate_mathtext_font], - 'mathtext.sf' : [('sans-serif', 'normal', 'normal'), validate_mathtext_font], + 'mathtext.cal' : [FontPropertiesProxy(['cursive']), validate_font_properties], + 'mathtext.rm' : [FontPropertiesProxy(['serif']), validate_font_properties], + 'mathtext.tt' : [FontPropertiesProxy(['monospace']), validate_font_properties], + 'mathtext.it' : [FontPropertiesProxy(['serif'], style='oblique'), validate_font_properties], + 'mathtext.bf' : [FontPropertiesProxy(['serif'], weight='bold'), validate_font_properties], + 'mathtext.sf' : [FontPropertiesProxy(['sans-serif']), validate_font_properties], 'mathtext.use_cm' : [True, validate_bool], 'mathtext.fallback_to_cm' : [True, validate_bool], Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-20 12:47:45 UTC (rev 3718) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-20 16:11:29 UTC (rev 3719) @@ -686,9 +686,7 @@ TruetypeFonts.__init__(self, *args, **kwargs) if not len(self.fontmap): for texfont in "cal rm tt it bf sf".split(): - setting = rcParams['mathtext.' + texfont] - family, weight, style = setting - prop = FontProperties(family=family, weight=weight, style=style) + prop = rcParams['mathtext.' + texfont] font = findfont(prop) self.fontmap[texfont] = font Modified: trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc =================================================================== --- trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc 2007-08-20 12:47:45 UTC (rev 3718) +++ trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc 2007-08-20 16:11:29 UTC (rev 3719) @@ -150,7 +150,7 @@ #text.dvipnghack : False # some versions of dvipng don't handle # alpha channel properly. Use True to correct and flush # ~/.matplotlib/tex.cache before testing -#text.markup : 'plain' # Affects how text, such as titles and lables, are +#text.markup : 'plain' # Affects how text, such as titles and labels, are # interpreted by default. # 'plain': As plain, unformatted text # 'tex': As TeX-like text. Text between $'s will be @@ -160,16 +160,16 @@ # processing. # The following settings allow you to select the fonts in math mode. -# They map from a TeX font name to a 3-tuple of the form: -# (family, weight, style) +# They map from a TeX font name to a set of arguments for the FontProperties constructor. +# (See FontProperties for more details). # These settings are only used if mathtext.use_cm is False, otherwise, the # Bakoma TeX Computer Modern fonts are used. -#mathtext.cal : (['cursive'], 'normal', 'normal') -#mathtext.rm : (['serif'], 'normal', 'normal') -#mathtext.tt : (['monospace'], 'normal', 'normal') -#mathtext.it : (['serif'], 'normal', 'oblique') -#mathtext.bf : (['serif'], 'bold', 'normal') -#mathtext.sf : (['sans-serif'], 'normal', 'normal') +#mathtext.cal : ['cursive'] +#mathtext.rm : ['serif'] +#mathtext.tt : ['monospace'] +#mathtext.it : ['serif'], style='oblique' +#mathtext.bf : ['serif'], weight='bold' +#mathtext.sf : ['sans-serif'] #mathtext.use_cm : True #mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern # fonts when a symbol can not be found in one of Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py =================================================================== --- trunk/matplotlib/lib/matplotlib/rcsetup.py 2007-08-20 12:47:45 UTC (rev 3718) +++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2007-08-20 16:11:29 UTC (rev 3719) @@ -198,12 +198,64 @@ except ValueError: raise ValueError('not a valid font size') -def validate_mathtext_font(s): - s = eval(s) - if type(s) in (list, tuple) and len(s) == 3: - return s - raise ValueError('Mathtext font specifier must be a 3-tuple of (family, weight, style)') +class FontPropertiesProxy: + # In order to build a FontProperties object, various rcParams must + # already be known in order to set default values. That means a + # FontProperties object can not be created from a config file, + # since it depends on other values in the same config file. This + # proxy class is used as a temporary storage area for the settings + # in the config file, and the full FontProperties class is created + # only when the class is first used. It is defined here rather than + # in font_manager.py to avoid a cyclical import. + def __init__(self, + family = None, + style = None, + variant= None, + weight = None, + stretch= None, + size = None, + fname = None, # if this is set, it's a hardcoded filename to use + ): + self.__family = family + self.__style = style + self.__variant = variant + self.__weight = weight + self.__stretch = stretch + self.__size = size + self.__fname = fname + + self.__child = None + + def __get_child(self): + if self.__child is None: + from font_manager import FontProperties + self.__child = FontProperties( + family = self.__family, + style = self.__style, + variant = self.__variant, + weight = self.__weight, + stretch = self.__stretch, + size = self.__size, + fname = self.__fname) + return self.__child + + def __getattr__(self, attr): + return getattr(self.__get_child(), attr) +def validate_font_properties(s): + parsed = False + try: + prop = eval(u'FontProperties(%s)' % s, + {}, {'FontProperties': FontPropertiesProxy}) + except: + pass + else: + parsed = isinstance(prop, FontPropertiesProxy) + if not parsed: + raise ValueError( + 'Mathtext font specifier must be a set of arguments to the FontProperty constructor.') + return prop + validate_markup = ValidateInStrings( 'markup', ['plain', 'tex'], @@ -366,12 +418,12 @@ 'text.fontsize' : ['medium', validate_fontsize], 'text.markup' : ['plain', validate_markup], - 'mathtext.cal' : [('cursive', 'normal', 'normal'), validate_mathtext_font], - 'mathtext.rm' : [('serif', 'normal', 'normal'), validate_mathtext_font], - 'mathtext.tt' : [('monospace', 'normal', 'normal'), validate_mathtext_font], - 'mathtext.it' : [('serif', 'normal', 'italic'), validate_mathtext_font], - 'mathtext.bf' : [('serif', 'bold', 'normal'), validate_mathtext_font], - 'mathtext.sf' : [('sans-serif', 'normal', 'normal'), validate_mathtext_font], + 'mathtext.cal' : [FontPropertiesProxy(['cursive']), validate_font_properties], + 'mathtext.rm' : [FontPropertiesProxy(['serif']), validate_font_properties], + 'mathtext.tt' : [FontPropertiesProxy(['monospace']), validate_font_properties], + 'mathtext.it' : [FontPropertiesProxy(['serif'], style='oblique'), validate_font_properties], + 'mathtext.bf' : [FontPropertiesProxy(['serif'], weight='bold'), validate_font_properties], + 'mathtext.sf' : [FontPropertiesProxy(['sans-serif']), validate_font_properties], 'mathtext.use_cm' : [True, validate_bool], 'mathtext.fallback_to_cm' : [True, validate_bool], Modified: trunk/matplotlib/matplotlibrc.template =================================================================== --- trunk/matplotlib/matplotlibrc.template 2007-08-20 12:47:45 UTC (rev 3718) +++ trunk/matplotlib/matplotlibrc.template 2007-08-20 16:11:29 UTC (rev 3719) @@ -150,7 +150,7 @@ #text.dvipnghack : False # some versions of dvipng don't handle # alpha channel properly. Use True to correct and flush # ~/.matplotlib/tex.cache before testing -#text.markup : 'plain' # Affects how text, such as titles and lables, are +#text.markup : 'plain' # Affects how text, such as titles and labels, are # interpreted by default. # 'plain': As plain, unformatted text # 'tex': As TeX-like text. Text between $'s will be @@ -160,16 +160,16 @@ # processing. # The following settings allow you to select the fonts in math mode. -# They map from a TeX font name to a 3-tuple of the form: -# (family, weight, style) +# They map from a TeX font name to a set of arguments for the FontProperties constructor. +# (See FontProperties for more details). # These settings are only used if mathtext.use_cm is False, otherwise, the # Bakoma TeX Computer Modern fonts are used. -#mathtext.cal : (['cursive'], 'normal', 'normal') -#mathtext.rm : (['serif'], 'normal', 'normal') -#mathtext.tt : (['monospace'], 'normal', 'normal') -#mathtext.it : (['serif'], 'normal', 'oblique') -#mathtext.bf : (['serif'], 'bold', 'normal') -#mathtext.sf : (['sans-serif'], 'normal', 'normal') +#mathtext.cal : ['cursive'] +#mathtext.rm : ['serif'] +#mathtext.tt : ['monospace'] +#mathtext.it : ['serif'], style='oblique' +#mathtext.bf : ['serif'], weight='bold' +#mathtext.sf : ['sans-serif'] #mathtext.use_cm : True #mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern # fonts when a symbol can not be found in one of This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ds...@us...> - 2007-08-20 18:52:40
|
Revision: 3720 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3720&view=rev Author: dsdale Date: 2007-08-20 11:52:38 -0700 (Mon, 20 Aug 2007) Log Message: ----------- fix verbose reporting with traited config Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/__init__.py trunk/matplotlib/setup.py Modified: trunk/matplotlib/lib/matplotlib/__init__.py =================================================================== --- trunk/matplotlib/lib/matplotlib/__init__.py 2007-08-20 16:11:29 UTC (rev 3719) +++ trunk/matplotlib/lib/matplotlib/__init__.py 2007-08-20 18:52:38 UTC (rev 3720) @@ -711,6 +711,8 @@ #print "importing from reorganized config system!" try: from config import rcParams, rcdefaults, mplConfig, save_config + verbose.set_level(rcParams['verbose.level']) + verbose.set_fileo(rcParams['verbose.fileo']) except: from config import rcParams, rcdefaults Modified: trunk/matplotlib/setup.py =================================================================== --- trunk/matplotlib/setup.py 2007-08-20 16:11:29 UTC (rev 3719) +++ trunk/matplotlib/setup.py 2007-08-20 18:52:38 UTC (rev 3720) @@ -64,7 +64,7 @@ try: import setuptools except ImportError: raise SystemExit("""\ -matplotlib requires setuptools for installation. Visit: +matplotlib requires setuptools for installation with python-2.3. Visit: http://cheeseshop.python.org/pypi/setuptools for installation instructions for the proper version of setuptools for your system. If this is your first time upgrading matplotlib with the new This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-21 17:26:00
|
Revision: 3724 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3724&view=rev Author: mdboom Date: 2007-08-21 10:25:57 -0700 (Tue, 21 Aug 2007) Log Message: ----------- Making parser more robust -- will only accept valid symbol names. (Re-)adding \hspace{ } command. Modified Paths: -------------- trunk/matplotlib/examples/mathtext_examples.py trunk/matplotlib/lib/matplotlib/_mathtext_data.py trunk/matplotlib/lib/matplotlib/mathtext.py Modified: trunk/matplotlib/examples/mathtext_examples.py =================================================================== --- trunk/matplotlib/examples/mathtext_examples.py 2007-08-21 15:24:26 UTC (rev 3723) +++ trunk/matplotlib/examples/mathtext_examples.py 2007-08-21 17:25:57 UTC (rev 3724) @@ -9,7 +9,7 @@ r'$100\%y\ x*y\ x/y x\$y$', r'$x\leftarrow y\ x\forall y\ x-y$', r'$x \sf x \bf x {\cal X} \rm x$', - r'$x\ x\,x\;x\quad x\qquad x\!x$', + r'$x\ x\,x\;x\quad x\qquad x\!x\hspace{0.5}y$', r'$\{ \rm braces \}$', r'$\left[\left\lfloor\frac{5}{\frac{\left(3\right)}{4}} y\right)\right]$', r'$\left(x\right)$', Modified: trunk/matplotlib/lib/matplotlib/_mathtext_data.py =================================================================== --- trunk/matplotlib/lib/matplotlib/_mathtext_data.py 2007-08-21 15:24:26 UTC (rev 3723) +++ trunk/matplotlib/lib/matplotlib/_mathtext_data.py 2007-08-21 17:25:57 UTC (rev 3724) @@ -1763,7 +1763,6 @@ 'Theta': 920, 'origof': 8886, 'blacksquare': 9632, -'hspace': 8202, 'solbar': 9023, 'neg': 172, 'sum': 8721, Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-21 15:24:26 UTC (rev 3723) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-21 17:25:57 UTC (rev 3724) @@ -1750,12 +1750,10 @@ _overunder_symbols = Set(r''' \sum \prod \coprod \bigcap \bigcup \bigsqcup \bigvee \bigwedge \bigodot \bigotimes \bigoplus \biguplus - '''.split() - ) + '''.split()) _overunder_functions = Set( - r"lim liminf limsup sup max min".split() - ) + r"lim liminf limsup sup max min".split()) _dropsub_symbols = Set(r'''\int \oint'''.split()) @@ -1769,11 +1767,13 @@ autoDelim = Forward().setParseAction(self.auto_sized_delimiter) self._expression = Forward().setParseAction(self.finish).setName("finish") + float = Regex(r"-?[0-9]+\.?[0-9]*") + lbrace = Literal('{').suppress() rbrace = Literal('}').suppress() start_group = (Optional(latexfont) + lbrace) start_group.setParseAction(self.start_group) - end_group = rbrace + end_group = rbrace.copy() end_group.setParseAction(self.end_group) bslash = Literal('\\') @@ -1786,15 +1786,9 @@ "cosh gcd ln sup cot hom log tan coth inf max " "tanh") - number = Combine(Word(nums) + Optional(Literal('.')) + Optional( Word(nums) )) - fontname = oneOf("rm cal it tt sf bf") latex2efont = oneOf("mathrm mathcal mathit mathtt mathsf mathbf") - texsym = Combine(bslash + Word(alphanums) + NotAny("{")) - - char = Word(alphanums + ' ', exact=1).leaveWhitespace() - space =(FollowedBy(bslash) + (Literal(r'\ ') | Literal(r'\/') @@ -1806,19 +1800,18 @@ ) ).setParseAction(self.space).setName('space') - symbol = Regex("(" + ")|(".join( - [ - r"\\(?!quad)(?!qquad)(?!left[^a-z])(?!right[^a-z])[a-zA-Z0-9]+(?!{)", - r"[a-zA-Z0-9 ]", - r"[+\-*/]", - r"[<>=]", - r"[:,.;!'@[()]", - r"\\[$%{}]", - ]) - + ")" - ).setParseAction(self.symbol).leaveWhitespace() + customspace =(Literal(r'\hspace') + + lbrace + + float + + rbrace + ).setParseAction(self.customspace).setName('customspace') - rightBracket = Literal("[").setParseAction(self.symbol).leaveWhitespace() + symbol =(Regex(r"[a-zA-Z0-9 +\-*/<>=:,.;!'@()[\]]") + ^ Combine( + bslash + + oneOf(tex2uni.keys()) + ) + ).setParseAction(self.symbol).leaveWhitespace() accent = Group( Combine(bslash + accent) @@ -1873,13 +1866,13 @@ placeable <<(accent ^ function ^ symbol - ^ rightBracket ^ group ^ frac ^ sqrt ) simple <<(space + | customspace | font | subsuper ) @@ -2016,6 +2009,9 @@ box = self._make_space(num) return [box] + def customspace(self, s, loc, toks): + return [self._make_space(float(toks[1]))] + def symbol(self, s, loc, toks): # print "symbol", toks c = toks[0] @@ -2226,7 +2222,8 @@ y = Hlist([sub]) # y.width += SCRIPT_SPACE * xHeight shift_down = max(shift_down, SUB1 * xHeight) - clr = 2.0 * rule_thickness - ((shift_up - x.depth) - (y.height - shift_down)) + clr = (2.0 * rule_thickness - + ((shift_up - x.depth) - (y.height - shift_down))) if clr > 0.: shift_up += clr shift_down += clr This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ef...@us...> - 2007-08-27 14:37:30
|
Revision: 3737 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3737&view=rev Author: efiring Date: 2007-08-25 23:56:07 -0700 (Sat, 25 Aug 2007) Log Message: ----------- Added step plot based on patch by Manuel Metz Modified Paths: -------------- trunk/matplotlib/boilerplate.py trunk/matplotlib/examples/masked_demo.py trunk/matplotlib/lib/matplotlib/axes.py trunk/matplotlib/lib/matplotlib/pylab.py Added Paths: ----------- trunk/matplotlib/examples/step_demo.py Modified: trunk/matplotlib/boilerplate.py =================================================================== --- trunk/matplotlib/boilerplate.py 2007-08-24 18:17:51 UTC (rev 3736) +++ trunk/matplotlib/boilerplate.py 2007-08-26 06:56:07 UTC (rev 3737) @@ -80,6 +80,7 @@ 'specgram', 'spy', 'stem', + 'step', 'vlines', 'quiver', 'quiverkey', Modified: trunk/matplotlib/examples/masked_demo.py =================================================================== --- trunk/matplotlib/examples/masked_demo.py 2007-08-24 18:17:51 UTC (rev 3736) +++ trunk/matplotlib/examples/masked_demo.py 2007-08-26 06:56:07 UTC (rev 3737) @@ -6,15 +6,15 @@ break the line at the data gaps. ''' -import matplotlib.numerix.ma as M +import matplotlib.numerix.npyma as ma from pylab import * -x = M.arange(0, 2*pi, 0.02) -y = M.sin(x) +x = ma.arange(0, 2*pi, 0.02) +y = ma.sin(x) y1 = sin(2*x) y2 = sin(3*x) -ym1 = M.masked_where(y1 > 0.5, y1) -ym2 = M.masked_where(y2 < -0.5, y2) +ym1 = ma.masked_where(y1 > 0.5, y1) +ym2 = ma.masked_where(y2 < -0.5, y2) lines = plot(x, y, 'r', x, ym1, 'g', x, ym2, 'bo') setp(lines[0], linewidth = 4) Added: trunk/matplotlib/examples/step_demo.py =================================================================== --- trunk/matplotlib/examples/step_demo.py (rev 0) +++ trunk/matplotlib/examples/step_demo.py 2007-08-26 06:56:07 UTC (rev 3737) @@ -0,0 +1,24 @@ +import numpy as npy +from pylab import * + +x = npy.arange(1, 7, 0.4) +y0 = npy.sin(x) +y = y0.copy() + 2.5 + +step(x, y, label='pre (default)') + +y -= 0.5 +step(x, y, where='mid', label='mid') + +y -= 0.5 +step(x, y, where='post', label='post') + +y = npy.ma.masked_where((y0>-0.15)&(y0<0.15), y - 0.5) +step(x,y, label='masked (pre)') + +legend() + +xlim(0, 7) +ylim(-0.5, 4) + +show() Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2007-08-24 18:17:51 UTC (rev 3736) +++ trunk/matplotlib/lib/matplotlib/axes.py 2007-08-26 06:56:07 UTC (rev 3737) @@ -2964,7 +2964,59 @@ #### Specialized plotting + def step(self, x, y, *args, **kwargs): + ''' + step(x, y, *args, **kwargs) + x and y must be 1-D sequences, and it is assumed, but not checked, + that x is uniformly increasing. + + Make a step plot. The args and keyword args to step are the same + as the args to plot. See help plot for more info. + + Additional keyword args for step: + + * where: can be 'pre', 'post' or 'mid'; if 'pre', the + interval from x[i] to x[i+1] has level y[i]; + if 'post', that interval has level y[i+1]; + and if 'mid', the jumps in y occur half-way + between the x-values. Default is 'pre'. + ''' + + where = kwargs.pop('where', 'pre') + + if not cbook.iterable(x): + x = ma.array([x], dtype=npy.float_) + if not cbook.iterable(y): + y = ma.array([y], dtype=npy.float_) + + if where=='pre': + x2 = ma.zeros((2*len(x)-1,), npy.float_) + y2 = ma.zeros((2*len(y)-1,), npy.float_) + + x2[0::2], x2[1::2] = x, x[:-1] + y2[0::2], y2[1:-1:2] = y, y[1:] + + elif where=='post': + x2 = ma.zeros((2*len(x)-1,), npy.float_) + y2 = ma.zeros((2*len(y)-1,), npy.float_) + + x2[::2], x2[1:-1:2] = x, x[1:] + y2[0::2], y2[1::2] = y, y[:-1] + + elif where=='mid': + x2 = ma.zeros((2*len(x),), npy.float_) + y2 = ma.zeros((2*len(y),), npy.float_) + + x2[1:-1:2] = 0.5*(x[:-1]+x[1:]) + x2[2::2] = 0.5*(x[:-1]+x[1:]) + x2[0], x2[-1] = x[0], x[-1] + + y2[0::2], y2[1::2] = y, y + + return self.plot(x2, y2, *args, **kwargs) + + def bar(self, left, height, width=0.8, bottom=None, color=None, edgecolor=None, linewidth=None, yerr=None, xerr=None, ecolor=None, capsize=3, Modified: trunk/matplotlib/lib/matplotlib/pylab.py =================================================================== --- trunk/matplotlib/lib/matplotlib/pylab.py 2007-08-24 18:17:51 UTC (rev 3736) +++ trunk/matplotlib/lib/matplotlib/pylab.py 2007-08-26 06:56:07 UTC (rev 3737) @@ -1555,7 +1555,7 @@ def acorr(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1576,7 +1576,7 @@ def arrow(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1597,7 +1597,7 @@ def axhline(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1618,7 +1618,7 @@ def axhspan(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1639,7 +1639,7 @@ def axvline(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1660,7 +1660,7 @@ def axvspan(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1681,7 +1681,7 @@ def bar(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1702,7 +1702,7 @@ def barh(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1723,7 +1723,7 @@ def broken_barh(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1744,7 +1744,7 @@ def boxplot(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1765,7 +1765,7 @@ def cohere(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1786,7 +1786,7 @@ def clabel(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1807,7 +1807,7 @@ def contour(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1828,7 +1828,7 @@ def contourf(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1849,7 +1849,7 @@ def csd(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1870,7 +1870,7 @@ def errorbar(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1891,7 +1891,7 @@ def fill(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1912,7 +1912,7 @@ def hist(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1933,7 +1933,7 @@ def hlines(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1954,7 +1954,7 @@ def imshow(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1975,7 +1975,7 @@ def loglog(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -1996,7 +1996,7 @@ def pcolor(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2017,7 +2017,7 @@ def pcolormesh(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2038,7 +2038,7 @@ def pie(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2059,7 +2059,7 @@ def plot(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2080,7 +2080,7 @@ def plot_date(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2101,7 +2101,7 @@ def psd(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2122,7 +2122,7 @@ def scatter(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2143,7 +2143,7 @@ def semilogx(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2164,7 +2164,7 @@ def semilogy(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2185,7 +2185,7 @@ def specgram(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2206,7 +2206,7 @@ def spy(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2227,7 +2227,7 @@ def stem(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2245,10 +2245,31 @@ # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost +def step(*args, **kwargs): + # allow callers to override the hold state by passing hold=True|False + b = ishold() + h = kwargs.pop('hold', None) + if h is not None: + hold(h) + try: + ret = gca().step(*args, **kwargs) + draw_if_interactive() + except: + hold(b) + raise + + hold(b) + return ret +if Axes.step.__doc__ is not None: + step.__doc__ = dedent(Axes.step.__doc__) + """ +Addition kwargs: hold = [True|False] overrides default hold state""" + +# This function was autogenerated by boilerplate.py. Do not edit as +# changes will be lost def vlines(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2269,7 +2290,7 @@ def quiver(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2290,7 +2311,7 @@ def quiverkey(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2311,7 +2332,7 @@ def xcorr(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False b = ishold() - h = popd(kwargs, 'hold', None) + h = kwargs.pop('hold', None) if h is not None: hold(h) try: @@ -2582,3 +2603,4 @@ draw_if_interactive() + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-27 19:33:51
|
Revision: 3741 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3741&view=rev Author: mdboom Date: 2007-08-27 12:33:45 -0700 (Mon, 27 Aug 2007) Log Message: ----------- Allow markup kwarg in more places. Modified Paths: -------------- trunk/matplotlib/examples/quiver_demo.py trunk/matplotlib/lib/matplotlib/legend.py trunk/matplotlib/lib/matplotlib/quiver.py trunk/matplotlib/lib/matplotlib/table.py Modified: trunk/matplotlib/examples/quiver_demo.py =================================================================== --- trunk/matplotlib/examples/quiver_demo.py 2007-08-27 19:32:38 UTC (rev 3740) +++ trunk/matplotlib/examples/quiver_demo.py 2007-08-27 19:33:45 UTC (rev 3741) @@ -17,8 +17,9 @@ #1 figure() Q = quiver( U, V) -qk = quiverkey(Q, 0.5, 0.92, 2, '2 m/s', labelpos='W', - fontproperties={'weight': 'bold'}) +qk = quiverkey(Q, 0.5, 0.92, 2, r'$2 \frac{m}{s}$', labelpos='W', + fontproperties={'weight': 'bold'}, + markup="tex") l,r,b,t = axis() dx, dy = r-l, t-b axis([l-0.05*dx, r+0.05*dx, b-0.05*dy, t+0.05*dy]) @@ -28,10 +29,11 @@ #2 figure() Q = quiver( X, Y, U, V, units='width') -qk = quiverkey(Q, 0.9, 0.95, 2, '2 m/s', - labelpos='E', - coordinates='figure', - fontproperties={'weight': 'bold'}) +qk = quiverkey(Q, 0.9, 0.95, 2, r'$2 \frac{m}{s}$', + labelpos='E', + coordinates='figure', + fontproperties={'weight': 'bold'}, + markup="tex") axis([-1, 7, -1, 7]) title('scales with plot width, not view') @@ -39,7 +41,7 @@ figure() Q = quiver( X[::3, ::3], Y[::3, ::3], U[::3, ::3], V[::3, ::3], pivot='mid', color='r', units='inches' ) -qk = quiverkey(Q, 0.5, 0.03, 1, '1 m/s', fontproperties={'weight': 'bold'}) +qk = quiverkey(Q, 0.5, 0.03, 1, r'$1 \frac{m}{s}$', fontproperties={'weight': 'bold'}, markup="tex") plot( X[::3, ::3], Y[::3, ::3], 'k.') axis([-1, 7, -1, 7]) title("pivot='mid'; every third arrow; units='inches'") @@ -48,9 +50,10 @@ figure() M = sqrt(pow(U, 2) + pow(V, 2)) Q = quiver( X, Y, U, V, M, units='x', pivot='tip', width=0.022, scale=1/0.15) -qk = quiverkey(Q, 0.9, 1.05, 1, '1 m/s', +qk = quiverkey(Q, 0.9, 1.05, 1, r'$1 \frac{m}{s}$', labelpos='E', - fontproperties={'weight': 'bold'}) + fontproperties={'weight': 'bold'}, + markup="tex") plot(X, Y, 'k.') axis([-1, 7, -1, 7]) title("scales with x view; pivot='tip'") @@ -60,7 +63,7 @@ Q = quiver( X[::3, ::3], Y[::3, ::3], U[::3, ::3], V[::3, ::3], color='r', units='x', linewidths=(2,), edgecolors=('k'), headaxislength=5 ) -qk = quiverkey(Q, 0.5, 0.03, 1, '1 m/s', fontproperties={'weight': 'bold'}) +qk = quiverkey(Q, 0.5, 0.03, 1, r'$1 \frac{m}{s}$', fontproperties={'weight': 'bold'}, markup="tex") axis([-1, 7, -1, 7]) title("triangular head; scale with x view; black edges") Modified: trunk/matplotlib/lib/matplotlib/legend.py =================================================================== --- trunk/matplotlib/lib/matplotlib/legend.py 2007-08-27 19:32:38 UTC (rev 3740) +++ trunk/matplotlib/lib/matplotlib/legend.py 2007-08-27 19:33:45 UTC (rev 3741) @@ -123,7 +123,8 @@ handletextsep = None, # the space between the legend line and legend text axespad = None, # the border between the axes and legend edge - shadow= None, + shadow = None, + markup = None ): """ parent # the artist that contains the legend @@ -203,7 +204,7 @@ else: self._xdata = npy.linspace(left, left + self.handlelen, self.numpoints) textleft = left+ self.handlelen+self.handletextsep - self.texts = self._get_texts(labels, textleft, top) + self.texts = self._get_texts(labels, textleft, top, markup) self.legendHandles = self._get_handles(handles, self.texts) @@ -404,7 +405,7 @@ 'return a list of text.Text instance in the legend' return silent_list('Text', self.texts) - def _get_texts(self, labels, left, upper): + def _get_texts(self, labels, left, upper, markup): # height in axes coords HEIGHT = self._approx_text_height() @@ -419,6 +420,7 @@ fontproperties=self.prop, verticalalignment='top', horizontalalignment='left', + markup=markup ) self._set_artist_props(text) ret.append(text) Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2007-08-27 19:32:38 UTC (rev 3740) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2007-08-27 19:33:45 UTC (rev 3741) @@ -173,12 +173,14 @@ self.labelpos = kw.pop('labelpos', 'N') self.labelcolor = kw.pop('labelcolor', None) self.fontproperties = kw.pop('fontproperties', dict()) + self.markup = kw.pop('markup', None) self.kw = kw _fp = self.fontproperties self.text = text.Text(text=label, horizontalalignment=self.halign[self.labelpos], verticalalignment=self.valign[self.labelpos], - fontproperties=font_manager.FontProperties(**_fp)) + fontproperties=font_manager.FontProperties(**_fp), + markup=self.markup) if self.labelcolor is not None: self.text.set_color(self.labelcolor) self._initialized = False Modified: trunk/matplotlib/lib/matplotlib/table.py =================================================================== --- trunk/matplotlib/lib/matplotlib/table.py 2007-08-27 19:32:38 UTC (rev 3740) +++ trunk/matplotlib/lib/matplotlib/table.py 2007-08-27 19:33:45 UTC (rev 3741) @@ -47,6 +47,8 @@ fill=True, text='', loc=None, + fontproperties=None, + markup=None ): # Call base @@ -58,7 +60,8 @@ # Create text object if loc is None: loc = 'right' self._loc = loc - self._text = Text(x=xy[0], y=xy[1], text=text) + self._text = Text(x=xy[0], y=xy[1], text=text, + fontproperties=fontproperties, markup=markup) self._text.set_clip_on(False) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-30 15:11:26
|
Revision: 3757 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3757&view=rev Author: mdboom Date: 2007-08-30 08:11:23 -0700 (Thu, 30 Aug 2007) Log Message: ----------- Remove the "markup" kwarg and rcParam everywhere and replace it with an automatic detection of math markup. Modified Paths: -------------- trunk/matplotlib/examples/accented_text.py trunk/matplotlib/examples/arrow_demo.py trunk/matplotlib/examples/dannys_example.py trunk/matplotlib/examples/histogram_demo.py trunk/matplotlib/examples/histogram_demo_canvasagg.py trunk/matplotlib/examples/integral_demo.py trunk/matplotlib/examples/legend_auto.py trunk/matplotlib/examples/mathtext_demo.py trunk/matplotlib/examples/mathtext_examples.py trunk/matplotlib/examples/quiver_demo.py trunk/matplotlib/examples/scatter_demo2.py trunk/matplotlib/examples/tex_demo.py trunk/matplotlib/examples/tex_unicode_demo.py trunk/matplotlib/examples/unicode_demo.py trunk/matplotlib/lib/matplotlib/config/mplconfig.py trunk/matplotlib/lib/matplotlib/config/rcsetup.py trunk/matplotlib/lib/matplotlib/legend.py trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/lib/matplotlib/quiver.py trunk/matplotlib/lib/matplotlib/rcsetup.py trunk/matplotlib/lib/matplotlib/table.py trunk/matplotlib/lib/matplotlib/text.py Modified: trunk/matplotlib/examples/accented_text.py =================================================================== --- trunk/matplotlib/examples/accented_text.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/accented_text.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -13,9 +13,9 @@ plot(range(10)) -title(r'$\ddot{o}\acute{e}\grave{e}\hat{O}\breve{i}\bar{A}\tilde{n}\vec{q}$', fontsize=20, markup="tex") +title(r'$\ddot{o}\acute{e}\grave{e}\hat{O}\breve{i}\bar{A}\tilde{n}\vec{q}$', fontsize=20) # shorthand is also supported and curly's are optional -xlabel(r"""$\"o\ddot o \'e\`e\~n\.x\^y$""", fontsize=20, markup="tex") +xlabel(r"""$\"o\ddot o \'e\`e\~n\.x\^y$""", fontsize=20) show() Modified: trunk/matplotlib/examples/arrow_demo.py =================================================================== --- trunk/matplotlib/examples/arrow_demo.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/arrow_demo.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -52,7 +52,7 @@ min_text_size = size label_text_size = size*2.5 text_params={'ha':'center', 'va':'center', 'family':'sans-serif',\ - 'fontweight':'bold', 'markup': 'tex'} + 'fontweight':'bold'} r2 = sqrt(2) deltas = {\ @@ -211,7 +211,7 @@ label = '$%s_{_{\mathrm{%s}}}$' % (orig_label[0], orig_label[1:]) text(x, y, label, size=label_text_size, ha='center', va='center', \ - color=labelcolor or fc, markup='tex') + color=labelcolor or fc) for p in positions.keys(): draw_arrow(p) Modified: trunk/matplotlib/examples/dannys_example.py =================================================================== --- trunk/matplotlib/examples/dannys_example.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/dannys_example.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -29,14 +29,14 @@ pylab.plot((-delta / 2, -delta / 2 + offset * 2), (height, height + offset), 'k', linewidth = 2) pylab.plot((delta / 2, delta / 2 - offset * 2), (height, height - offset), 'k', linewidth = 2) pylab.plot((delta / 2, delta / 2 - offset * 2), (height, height + offset), 'k', linewidth = 2) -pylab.text(-0.06, height - 0.06, r'$\delta$', {'color' : 'k', 'fontsize' : 24}, markup = 'tex') +pylab.text(-0.06, height - 0.06, r'$\delta$', {'color' : 'k', 'fontsize' : 24}) ## X-axis label pylab.xticks((-1, 0, 1), ('-1', '0', '1'), color = 'k', size = 20) ## Left Y-axis labels pylab.ylabel(r'\bf{phase field} $\phi$', {'color' : 'b', - 'fontsize' : 20 }, markup='tex') + 'fontsize' : 20 }) pylab.yticks((0, 0.5, 1), ('0', '.5', '1'), color = 'k', size = 20) ## Right Y-axis labels @@ -44,17 +44,16 @@ horizontalalignment = 'left', verticalalignment = 'center', rotation = 90, - clip_on = False, - markup = 'tex') + clip_on = False) pylab.text(1.01, -0.02, "-1", {'color' : 'k', 'fontsize' : 20}) pylab.text(1.01, 0.98, "1", {'color' : 'k', 'fontsize' : 20}) pylab.text(1.01, 0.48, "0", {'color' : 'k', 'fontsize' : 20}) ## level set equations -pylab.text(0.1, 0.85, r'$|\nabla\phi| = 1,$ \newline $ \frac{\partial \phi}{\partial t} + U|\nabla \phi| = 0$', {'color' : 'g', 'fontsize' : 20}, markup='tex') +pylab.text(0.1, 0.85, r'$|\nabla\phi| = 1,$ \newline $ \frac{\partial \phi}{\partial t} + U|\nabla \phi| = 0$', {'color' : 'g', 'fontsize' : 20}) ## phase field equations -pylab.text(0.2, 0.15, r'$\mathcal{F} = \int f\left( \phi, c \right) dV,$ \newline $ \frac{ \partial \phi } { \partial t } = -M_{ \phi } \frac{ \delta \mathcal{F} } { \delta \phi }$', {'color' : 'b', 'fontsize' : 20}, markup='tex') +pylab.text(0.2, 0.15, r'$\mathcal{F} = \int f\left( \phi, c \right) dV,$ \newline $ \frac{ \partial \phi } { \partial t } = -M_{ \phi } \frac{ \delta \mathcal{F} } { \delta \phi }$', {'color' : 'b', 'fontsize' : 20}) pylab.savefig('pfm-lsm.png') pylab.show() Modified: trunk/matplotlib/examples/histogram_demo.py =================================================================== --- trunk/matplotlib/examples/histogram_demo.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/histogram_demo.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -15,7 +15,7 @@ xlabel('Smarts') ylabel('Probability') -title(r'$\mathrm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$', markup='tex') +title(r'$\mathrm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$') axis([40, 160, 0, 0.03]) grid(True) Modified: trunk/matplotlib/examples/histogram_demo_canvasagg.py =================================================================== --- trunk/matplotlib/examples/histogram_demo_canvasagg.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/histogram_demo_canvasagg.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -33,7 +33,7 @@ ax.set_xlabel('Smarts') ax.set_ylabel('Probability') -ax.set_title(r'$\mathrm{Histogram of IQ: }\mu=100, \sigma=15$', markup='tex') +ax.set_title(r'$\mathrm{Histogram of IQ: }\mu=100, \sigma=15$') ax.set_xlim( (40, 160)) ax.set_ylim( (0, 0.03)) Modified: trunk/matplotlib/examples/integral_demo.py =================================================================== --- trunk/matplotlib/examples/integral_demo.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/integral_demo.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -23,7 +23,7 @@ text(0.5 * (a + b), 30, r"$\int_a^b f(x)\mathrm{d}x$", horizontalalignment='center', - fontsize=20, markup='tex') + fontsize=20) axis([0,10, 0, 180]) figtext(0.9, 0.05, 'x') Modified: trunk/matplotlib/examples/legend_auto.py =================================================================== --- trunk/matplotlib/examples/legend_auto.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/legend_auto.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -51,9 +51,9 @@ def fig_7(): figure(7) xx = x - (N/2.0) - plot(xx, (xx*xx)-1225, 'bo', label='$y=x^2$', markup='tex') - plot(xx, 25*xx, 'go', label='$y=25x$', markup='tex') - plot(xx, -25*xx, 'mo', label='$y=-25x$', markup='tex') + plot(xx, (xx*xx)-1225, 'bo', label='$y=x^2$') + plot(xx, 25*xx, 'go', label='$y=25x$') + plot(xx, -25*xx, 'mo', label='$y=-25x$') legend() def fig_8(): Modified: trunk/matplotlib/examples/mathtext_demo.py =================================================================== --- trunk/matplotlib/examples/mathtext_demo.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/mathtext_demo.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -13,12 +13,14 @@ x = npy.arange(0.0, 3.0, 0.1) ax.grid(True) -ax.set_xlabel(r'$\Delta_i^j$', fontsize=20, markup="tex") -ax.set_ylabel(r'$\Delta_{i+1}^j$', fontsize=20, markup="tex") +ax.set_xlabel(r'$\Delta_i^j$', fontsize=20) +ax.set_ylabel(r'$\Delta_{i+1}^j$', fontsize=20) tex = r'$\mathcal{R}\prod_{i=\alpha_{i+1}}^\infty a_i\sin(2 \pi f x_i)$' -ax.text(1, 1.6, tex, fontsize=20, va='bottom', markup="tex") +ax.text(1, 1.6, tex, fontsize=20, va='bottom') +ax.legend(("Foo", "Testing $x^2$")) + #title(r'$\Delta_i^j \hspace{0.4} \rm{versus} \hspace{0.4} \Delta_{i+1}^j$', fontsize=20) fig.savefig('mathtext_demo') Modified: trunk/matplotlib/examples/mathtext_examples.py =================================================================== --- trunk/matplotlib/examples/mathtext_examples.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/mathtext_examples.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -2,14 +2,18 @@ import os, sys, re +import gc + stests = [ r'Kerning: AVA $AVA$', + r'\$100.00 $\alpha$', + r'$\frac{\$100.00}{y}$', r'$x y$', r'$x+y\ x=y\ x<y\ x:y\ x,y\ x@y$', r'$100\%y\ x*y\ x/y x\$y$', r'$x\leftarrow y\ x\forall y\ x-y$', r'$x \sf x \bf x {\cal X} \rm x$', - r'$x\ x\,x\;x\quad x\qquad x\!x\hspace{0.5}y$', + r'$x\ x\,x\;x\quad x\qquad x\!x\hspace{ 0.5 }y$', r'$\{ \rm braces \}$', r'$\left[\left\lfloor\frac{5}{\frac{\left(3\right)}{4}} y\right)\right]$', r'$\left(x\right)$', @@ -59,10 +63,10 @@ yticks(arange(len(tests)) * -1) for i, s in enumerate(tests): print "%02d: %s" % (i, s) - text(0.1, -i, s, fontsize=20, markup="tex") + text(0.1, -i, s, fontsize=20) savefig('mathtext_example') - figure() + close('all') if '--latex' in sys.argv: fd = open("mathtext_examples.ltx", "w") Modified: trunk/matplotlib/examples/quiver_demo.py =================================================================== --- trunk/matplotlib/examples/quiver_demo.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/quiver_demo.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -18,8 +18,7 @@ figure() Q = quiver( U, V) qk = quiverkey(Q, 0.5, 0.92, 2, r'$2 \frac{m}{s}$', labelpos='W', - fontproperties={'weight': 'bold'}, - markup="tex") + fontproperties={'weight': 'bold'}) l,r,b,t = axis() dx, dy = r-l, t-b axis([l-0.05*dx, r+0.05*dx, b-0.05*dy, t+0.05*dy]) @@ -32,8 +31,7 @@ qk = quiverkey(Q, 0.9, 0.95, 2, r'$2 \frac{m}{s}$', labelpos='E', coordinates='figure', - fontproperties={'weight': 'bold'}, - markup="tex") + fontproperties={'weight': 'bold'}) axis([-1, 7, -1, 7]) title('scales with plot width, not view') @@ -41,7 +39,7 @@ figure() Q = quiver( X[::3, ::3], Y[::3, ::3], U[::3, ::3], V[::3, ::3], pivot='mid', color='r', units='inches' ) -qk = quiverkey(Q, 0.5, 0.03, 1, r'$1 \frac{m}{s}$', fontproperties={'weight': 'bold'}, markup="tex") +qk = quiverkey(Q, 0.5, 0.03, 1, r'$1 \frac{m}{s}$', fontproperties={'weight': 'bold'}) plot( X[::3, ::3], Y[::3, ::3], 'k.') axis([-1, 7, -1, 7]) title("pivot='mid'; every third arrow; units='inches'") @@ -52,8 +50,7 @@ Q = quiver( X, Y, U, V, M, units='x', pivot='tip', width=0.022, scale=1/0.15) qk = quiverkey(Q, 0.9, 1.05, 1, r'$1 \frac{m}{s}$', labelpos='E', - fontproperties={'weight': 'bold'}, - markup="tex") + fontproperties={'weight': 'bold'}) plot(X, Y, 'k.') axis([-1, 7, -1, 7]) title("scales with x view; pivot='tip'") @@ -63,7 +60,7 @@ Q = quiver( X[::3, ::3], Y[::3, ::3], U[::3, ::3], V[::3, ::3], color='r', units='x', linewidths=(2,), edgecolors=('k'), headaxislength=5 ) -qk = quiverkey(Q, 0.5, 0.03, 1, r'$1 \frac{m}{s}$', fontproperties={'weight': 'bold'}, markup="tex") +qk = quiverkey(Q, 0.5, 0.03, 1, r'$1 \frac{m}{s}$', fontproperties={'weight': 'bold'}) axis([-1, 7, -1, 7]) title("triangular head; scale with x view; black edges") Modified: trunk/matplotlib/examples/scatter_demo2.py =================================================================== --- trunk/matplotlib/examples/scatter_demo2.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/scatter_demo2.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -11,8 +11,8 @@ close = 0.003*intc.close[:-2]/0.003*intc.open[:-2] p = scatter(delta1[:-1], delta1[1:], c=close, s=volume, alpha=0.75) -xlabel(r'$\Delta_i$', size='x-large', markup='tex') -ylabel(r'$\Delta_{i+1}$', size='x-large', markup='tex') +xlabel(r'$\Delta_i$', size='x-large') +ylabel(r'$\Delta_{i+1}$', size='x-large') title(r'Volume and percent change') grid(True) #savefig('scatter_demo2') Modified: trunk/matplotlib/examples/tex_demo.py =================================================================== --- trunk/matplotlib/examples/tex_demo.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/tex_demo.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -23,10 +23,10 @@ s = cos(2*2*pi*t)+2 plot(t, s) -xlabel(r'\textbf{time (s)}', markup='tex') -ylabel(r'\textit{voltage (mV)}',fontsize=16, markup='tex') +xlabel(r'\textbf{time (s)}') +ylabel(r'\textit{voltage (mV)}',fontsize=16) title(r"\TeX\ is Number $\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!", - fontsize=16, color='r', markup='tex') + fontsize=16, color='r') grid(True) savefig('tex_demo') Modified: trunk/matplotlib/examples/tex_unicode_demo.py =================================================================== --- trunk/matplotlib/examples/tex_unicode_demo.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/tex_unicode_demo.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -17,11 +17,11 @@ s = cos(2*2*pi*t)+2 plot(t, s) -xlabel(r'\textbf{time (s)}', markup='tex') +xlabel(r'\textbf{time (s)}') s = unicode(r'\textit{Velocity (\xB0/sec)}','latin-1') -ylabel(unicode(r'\textit{Velocity (\xB0/sec)}','latin-1'),fontsize=16, markup='tex') +ylabel(unicode(r'\textit{Velocity (\xB0/sec)}','latin-1'),fontsize=16) title(r"\TeX\ is Number $\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!", - fontsize=16, color='r', markup='tex') + fontsize=16, color='r') grid(True) savefig('tex_demo') Modified: trunk/matplotlib/examples/unicode_demo.py =================================================================== --- trunk/matplotlib/examples/unicode_demo.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/examples/unicode_demo.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -9,5 +9,5 @@ text( 0.5, 2.5, unicode('Institut f\xFCr Festk\xF6rperphysik', 'latin-1'), rotation=45) text( 1, 1.5, u'AVA (check kerning)') -savefig('test.svg') +savefig('test') show() Modified: trunk/matplotlib/lib/matplotlib/config/mplconfig.py =================================================================== --- trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -153,7 +153,6 @@ class text(TConfig): color = T.Trait('black',mplT.ColorHandler()) usetex = T.false - markup = T.Trait('plain', 'plain', 'tex') class latex(TConfig): unicode = T.false Modified: trunk/matplotlib/lib/matplotlib/config/rcsetup.py =================================================================== --- trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -203,11 +203,6 @@ parse_fontconfig_pattern(s) return s -validate_markup = ValidateInStrings( - 'markup', - ['plain', 'tex'], - ignorecase=True) - validate_verbose = ValidateInStrings('verbose',[ 'silent', 'helpful', 'debug', 'debug-annoying', ]) @@ -363,7 +358,6 @@ 'text.fontvariant' : ['normal', str], 'text.fontweight' : ['normal', str], 'text.fontsize' : ['medium', validate_fontsize], - 'text.markup' : ['plain', validate_markup], 'mathtext.cal' : ['cursive', validate_font_properties], 'mathtext.rm' : ['serif', validate_font_properties], Modified: trunk/matplotlib/lib/matplotlib/legend.py =================================================================== --- trunk/matplotlib/lib/matplotlib/legend.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/lib/matplotlib/legend.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -123,8 +123,7 @@ handletextsep = None, # the space between the legend line and legend text axespad = None, # the border between the axes and legend edge - shadow = None, - markup = None + shadow = None ): """ parent # the artist that contains the legend @@ -204,7 +203,7 @@ else: self._xdata = npy.linspace(left, left + self.handlelen, self.numpoints) textleft = left+ self.handlelen+self.handletextsep - self.texts = self._get_texts(labels, textleft, top, markup) + self.texts = self._get_texts(labels, textleft, top) self.legendHandles = self._get_handles(handles, self.texts) @@ -405,7 +404,7 @@ 'return a list of text.Text instance in the legend' return silent_list('Text', self.texts) - def _get_texts(self, labels, left, upper, markup): + def _get_texts(self, labels, left, upper): # height in axes coords HEIGHT = self._approx_text_height() @@ -419,8 +418,7 @@ text=l, fontproperties=self.prop, verticalalignment='top', - horizontalalignment='left', - markup=markup + horizontalalignment='left' ) self._set_artist_props(text) ret.append(text) Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -1982,7 +1982,7 @@ math_delim =(~bslash + Literal('$')) - non_math = Regex(r"(?:[^$]|(?:\\\$))*" + non_math = Regex(r"(?:(?:\\[$])|[^$])*" ).setParseAction(self.non_math).setName("non_math").leaveWhitespace() self._expression << ( @@ -2056,7 +2056,8 @@ def non_math(self, s, loc, toks): #~ print "non_math", toks - symbols = [Char(c, self.get_state()) for c in toks[0]] + s = toks[0].replace(r'\$', '$') + symbols = [Char(c, self.get_state()) for c in s] hlist = Hlist(symbols) # We're going into math now, so set font to 'it' self.push_state() Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -173,14 +173,12 @@ self.labelpos = kw.pop('labelpos', 'N') self.labelcolor = kw.pop('labelcolor', None) self.fontproperties = kw.pop('fontproperties', dict()) - self.markup = kw.pop('markup', None) self.kw = kw _fp = self.fontproperties self.text = text.Text(text=label, horizontalalignment=self.halign[self.labelpos], verticalalignment=self.valign[self.labelpos], - fontproperties=font_manager.FontProperties(**_fp), - markup=self.markup) + fontproperties=font_manager.FontProperties(**_fp)) if self.labelcolor is not None: self.text.set_color(self.labelcolor) self._initialized = False Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py =================================================================== --- trunk/matplotlib/lib/matplotlib/rcsetup.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -203,11 +203,6 @@ parse_fontconfig_pattern(s) return s -validate_markup = ValidateInStrings( - 'markup', - ['plain', 'tex'], - ignorecase=True) - validate_verbose = ValidateInStrings('verbose',[ 'silent', 'helpful', 'debug', 'debug-annoying', ]) @@ -363,7 +358,6 @@ 'text.fontvariant' : ['normal', str], 'text.fontweight' : ['normal', str], 'text.fontsize' : ['medium', validate_fontsize], - 'text.markup' : ['plain', validate_markup], 'mathtext.cal' : ['cursive', validate_font_properties], 'mathtext.rm' : ['serif', validate_font_properties], Modified: trunk/matplotlib/lib/matplotlib/table.py =================================================================== --- trunk/matplotlib/lib/matplotlib/table.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/lib/matplotlib/table.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -47,8 +47,7 @@ fill=True, text='', loc=None, - fontproperties=None, - markup=None + fontproperties=None ): # Call base @@ -61,7 +60,7 @@ if loc is None: loc = 'right' self._loc = loc self._text = Text(x=xy[0], y=xy[1], text=text, - fontproperties=fontproperties, markup=markup) + fontproperties=fontproperties) self._text.set_clip_on(False) Modified: trunk/matplotlib/lib/matplotlib/text.py =================================================================== --- trunk/matplotlib/lib/matplotlib/text.py 2007-08-30 13:51:10 UTC (rev 3756) +++ trunk/matplotlib/lib/matplotlib/text.py 2007-08-30 15:11:23 UTC (rev 3757) @@ -146,7 +146,6 @@ fontproperties=None, # defaults to FontProperties() rotation=None, linespacing=None, - markup=None, **kwargs ): """ @@ -176,7 +175,6 @@ if linespacing is None: linespacing = 1.2 # Maybe use rcParam later. self._linespacing = linespacing - self.set_markup(markup) self.update(kwargs) #self.set_bbox(dict(pad=0)) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd @@ -225,7 +223,6 @@ self._rotation = other._rotation self._picker = other._picker self._linespacing = other._linespacing - self._markup = other._markup def _get_layout(self, renderer): @@ -757,9 +754,14 @@ def is_math_text(self): if rcParams['text.usetex']: return 'TeX' - if self._markup.lower() == 'tex': - if not matplotlib._havemath: return False + + # Did we find an even number of non-escaped dollar signs? + # If so, treat is as math text. + s = self._text + dollar_count = s.count(r'$') - s.count(r'\$') + if dollar_count > 0 and dollar_count % 2 == 0: return True + return False def set_fontproperties(self, fp): @@ -770,20 +772,6 @@ """ self._fontproperties = fp - def set_markup(self, markup): - """ - Set the type of markup used for this text. - - ACCEPTS: 'plain' for plain text, 'tex' for TeX-like markup - None to use the default text.markup value. - """ - if markup is None: - self._markup = rcParams['text.markup'] - elif markup.lower() in ('plain', 'tex'): - self._markup = markup.lower() - else: - raise ValueError("Markup type must be 'plain' or 'tex'") - def _get_layout_super(self, renderer, m): """ a special case optimization if a log super and angle = 0 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-08-31 19:25:20
|
Revision: 3764 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3764&view=rev Author: mdboom Date: 2007-08-31 12:25:17 -0700 (Fri, 31 Aug 2007) Log Message: ----------- Render all the fonts in each mathtext expression to a single image buffer (memory and time savings). Add support for getting raw image data for mathtext expressions. Add mathtext_wx.py example showing how to put mathtext expressions into controls. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py trunk/matplotlib/lib/matplotlib/backends/backend_gdk.py trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/src/_backend_agg.cpp trunk/matplotlib/src/_backend_agg.h trunk/matplotlib/src/ft2font.cpp trunk/matplotlib/src/ft2font.h trunk/matplotlib/unit/agg_memleak.py Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007-08-31 17:23:32 UTC (rev 3763) +++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007-08-31 19:25:17 UTC (rev 3764) @@ -172,7 +172,7 @@ """ if __debug__: verbose.report('RendererAgg.draw_mathtext', 'debug-annoying') - ox, oy, width, height, descent, fonts, used_characters = \ + ox, oy, width, height, descent, font_image, used_characters = \ self.mathtext_parser.parse(s, self.dpi.get(), prop) if angle == 90: @@ -180,13 +180,11 @@ ox, oy = oy, ox x = int(x) - width + ox y = int(y) - height + oy + font_image.rotate() else: x = int(x) + ox y = int(y) - height + oy - for font in fonts: - if angle == 90: - font.horiz_image_to_vert_image() # <-- Rotate - self._renderer.draw_text( font, x, y + 1, gc) + self._renderer.draw_text_image(font_image, x, y + 1, gc) if 0: self._renderer.draw_rectangle(gc, None, int(x), @@ -212,7 +210,7 @@ #print x, y, int(x), int(y) - self._renderer.draw_text(font, int(x), int(y) + 1, gc) + self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, gc) def get_text_width_height_descent(self, s, prop, ismath, rgb=(0,0,0)): Modified: trunk/matplotlib/lib/matplotlib/backends/backend_gdk.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_gdk.py 2007-08-31 17:23:32 UTC (rev 3763) +++ trunk/matplotlib/lib/matplotlib/backends/backend_gdk.py 2007-08-31 19:25:17 UTC (rev 3764) @@ -215,7 +215,7 @@ for i, font in enumerate(fonts): if angle == 90: - font.horiz_image_to_vert_image() # <-- Rotate + font.get_image().rotate() # <-- Rotate imw, imh, image_str = font.image_as_str() Xall[:,i] = npy.fromstring(image_str, npy.uint8) Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-31 17:23:32 UTC (rev 3763) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-31 19:25:17 UTC (rev 3764) @@ -143,7 +143,7 @@ from matplotlib.afm import AFM from matplotlib.cbook import enumerate, iterable, Bunch, get_realpath_and_stat, \ is_string_like -from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_DEFAULT, LOAD_NO_HINTING +from matplotlib.ft2font import FT2Font, FT2Image, KERNING_DEFAULT, LOAD_DEFAULT, LOAD_NO_HINTING from matplotlib.font_manager import findfont, FontProperties from matplotlib._mathtext_data import latex_to_bakoma, \ latex_to_standard, tex2uni, type12uni, tex2type1, uni2type1 @@ -288,20 +288,19 @@ def __init__(self): self.ox = 0 self.oy = 0 + self.image = None MathtextBackend.__init__(self) def set_canvas_size(self, w, h, d): MathtextBackend.set_canvas_size(self, w, h, d) - for font in self.fonts_object.get_fonts(): - font.set_bitmap_size(int(w), int(h) + int(d)) + self.image = FT2Image(ceil(w), ceil(h + d)) def render_glyph(self, ox, oy, info): info.font.draw_glyph_to_bitmap( - ox, oy - info.metrics.ymax, info.glyph) + self.image, ox, oy - info.metrics.ymax, info.glyph) def render_rect_filled(self, x1, y1, x2, y2): - font = self.fonts_object.get_fonts()[0] - font.draw_rect_filled(x1, y1, x2, max(y2 - 1, y1)) + self.image.draw_rect_filled(x1, y1, x2, max(y2 - 1, y1)) def get_results(self, box): return (self.ox, @@ -309,7 +308,7 @@ self.width, self.height + self.depth, self.depth, - self.fonts_object.get_fonts(), + self.image, self.fonts_object.get_used_characters()) def get_hinting_type(self): @@ -318,6 +317,13 @@ def MathtextBackendAgg(): return MathtextBackendBbox(MathtextBackendAggRender()) +class MathtextBackendBitmapRender(MathtextBackendAggRender): + def get_results(self, box): + return self.image + +def MathtextBackendBitmap(): + return MathtextBackendBbox(MathtextBackendBitmapRender()) + class MathtextBackendPs(MathtextBackend): def __init__(self): self.pswriter = StringIO() @@ -2443,6 +2449,7 @@ _parser = None _backend_mapping = { + 'Bitmap': MathtextBackendBitmap, 'Agg' : MathtextBackendAgg, 'PS' : MathtextBackendPs, 'Pdf' : MathtextBackendPdf, @@ -2454,7 +2461,10 @@ self._output = output self._cache = {} - def parse(self, s, dpi, prop): + def parse(self, s, dpi = 72, prop = None): + if prop is None: + prop = FontProperties() + cacheKey = (s, dpi, hash(prop)) result = self._cache.get(cacheKey) if result is not None: Modified: trunk/matplotlib/src/_backend_agg.cpp =================================================================== --- trunk/matplotlib/src/_backend_agg.cpp 2007-08-31 17:23:32 UTC (rev 3763) +++ trunk/matplotlib/src/_backend_agg.cpp 2007-08-31 19:25:17 UTC (rev 3764) @@ -2106,14 +2106,15 @@ Py::Object -RendererAgg::draw_text(const Py::Tuple& args) { +RendererAgg::draw_text_image(const Py::Tuple& args) { _VERBOSE("RendererAgg::draw_text"); args.verify_length(4); + FT2Image *image = static_cast<FT2Image*>(args[0].ptr()); + if (!image->get_buffer()) + return Py::Object(); - FT2Font *font = static_cast<FT2Font*>(args[0].ptr()); - int x(0),y(0); try { x = Py::Int( args[1] ); @@ -2151,15 +2152,16 @@ t = b+h; } + const unsigned char* const buffer = image->get_buffer(); - for (size_t i=0; i<font->image.width; i++) { - for (size_t j=0; j<font->image.height; j++) { - thisx = i+x+font->image.offsetx; - thisy = j+y+font->image.offsety; + for (size_t i=0; i< image->get_width(); i++) { + for (size_t j=0; j< image->get_height(); j++) { + thisx = i+x+image->offsetx; + thisy = j+y+image->offsety; if (thisx<l || thisx>=r) continue; if (thisy<height-t || thisy>=height-b) continue; pixFmt->blend_pixel - (thisx, thisy, p, font->image.buffer[i + j*font->image.width]); + (thisx, thisy, p, buffer[i + j*image->get_width()]); } } @@ -2568,8 +2570,8 @@ "draw_markers(gc, path, x, y)\n"); add_varargs_method("draw_path", &RendererAgg::draw_path, "draw_path(gc, rgbFace, path, transform)\n"); - add_varargs_method("draw_text", &RendererAgg::draw_text, - "draw_text(font, x, y, r, g, b, a)\n"); + add_varargs_method("draw_text_image", &RendererAgg::draw_text_image, + "draw_text_image(font_image, x, y, r, g, b, a)\n"); add_varargs_method("draw_image", &RendererAgg::draw_image, "draw_image(x, y, im)"); add_varargs_method("write_rgba", &RendererAgg::write_rgba, Modified: trunk/matplotlib/src/_backend_agg.h =================================================================== --- trunk/matplotlib/src/_backend_agg.h 2007-08-31 17:23:32 UTC (rev 3763) +++ trunk/matplotlib/src/_backend_agg.h 2007-08-31 19:25:17 UTC (rev 3764) @@ -166,7 +166,7 @@ //Py::Object _draw_markers_nocache(const Py::Tuple & args); //Py::Object _draw_markers_cache(const Py::Tuple & args); Py::Object draw_markers(const Py::Tuple & args); - Py::Object draw_text(const Py::Tuple & args); + Py::Object draw_text_image(const Py::Tuple & args); Py::Object draw_image(const Py::Tuple & args); Py::Object write_rgba(const Py::Tuple & args); Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007-08-31 17:23:32 UTC (rev 3763) +++ trunk/matplotlib/src/ft2font.cpp 2007-08-31 19:25:17 UTC (rev 3764) @@ -42,9 +42,414 @@ FT_Library _ft2Library; -FT2Image::FT2Image() : bRotated(false), buffer(NULL) {} -FT2Image::~FT2Image() {delete [] buffer; buffer=NULL;} +FT2Image::FT2Image() : + offsetx(0), offsety(0), + _bRotated(false), + _isDirty(true), + _buffer(NULL), + _width(0), _height(0), + _rgbCopy(NULL), + _rgbaCopy(NULL) { + _VERBOSE("FT2Image::FT2Image"); +} +FT2Image::FT2Image(unsigned long width, unsigned long height) : + offsetx(0), offsety(0), + _bRotated(false), + _isDirty(true), + _buffer(NULL), + _width(0), _height(0), + _rgbCopy(NULL), + _rgbaCopy(NULL) { + _VERBOSE("FT2Image::FT2Image"); + resize(width, height); +} + +FT2Image::~FT2Image() { + _VERBOSE("FT2Image::~FT2Image"); + delete [] _buffer; + _buffer=NULL; +} + +void FT2Image::resize(unsigned long width, unsigned long height) { + size_t numBytes = width*height; + + if (_width != width || _height != height) { + _width = width; + _height = height; + + delete [] _buffer; + _buffer = new unsigned char [numBytes]; + } + + for (size_t n=0; n<numBytes; n++) + _buffer[n] = 0; + + _bRotated = false; + _isDirty = true; +} + +char FT2Image::resize__doc__[] = +"resize(width, height)\n" +"\n" +"Resize the dimensions of the image (it is cleared in the process).\n" +; +Py::Object +FT2Image::py_resize(const Py::Tuple & args) { + _VERBOSE("FT2Image::resize"); + + args.verify_length(2); + + long x0 = Py::Int(args[0]); + long y0 = Py::Int(args[1]); + + resize(x0, y0); + + return Py::Object(); +} + +void FT2Image::clear() { + _VERBOSE("FT2Image::clear"); + + _width = 0; + _height = 0; + offsetx = 0; + offsety = 0; + _isDirty = true; + _bRotated = false; + delete [] _buffer; + _buffer = NULL; + if (_rgbCopy) { + delete _rgbCopy; + _rgbCopy = NULL; + } + if (_rgbaCopy) { + delete _rgbaCopy; + _rgbaCopy = NULL; + } +} +char FT2Image::clear__doc__[] = +"clear()\n" +"\n" +"Clear the contents of the image.\n" +; +Py::Object +FT2Image::py_clear(const Py::Tuple & args) { + args.verify_length(0); + + clear(); + + return Py::Object(); +} + +void FT2Image::rotate() { + // If we have already rotated, just return. + if (_bRotated) + return; + + unsigned long width = _width; + unsigned long height = _height; + + unsigned long newWidth = _height; + unsigned long newHeight = _width; + + unsigned long numBytes = _width * _height; + + unsigned char * buffer = new unsigned char [numBytes]; + + unsigned long i, j, k, offset, nhMinusOne; + + nhMinusOne = newHeight - 1; + + unsigned char * read_it = _buffer; + + for (i=0; i<height; i++) { + offset = i*width; + for (j=0; j<width; j++) { + k = nhMinusOne - j; + buffer[i + k*newWidth] = *(read_it++); + } + } + + delete [] _buffer; + _buffer = buffer; + _width = newWidth; + _height = newHeight; + _bRotated = true; + _isDirty = true; +} +char FT2Image::rotate__doc__[] = +"rotate()\n" +"\n" +"Rotates the image 90 degrees.\n" +; +Py::Object +FT2Image::py_rotate(const Py::Tuple & args) { + _VERBOSE("FT2Image::rotate"); + + args.verify_length(0); + + rotate(); + + return Py::Object(); +} + +void +FT2Image::draw_bitmap( FT_Bitmap* bitmap, + FT_Int x, + FT_Int y) { + _VERBOSE("FT2Image::draw_bitmap"); + FT_Int image_width = (FT_Int)_width; + FT_Int image_height = (FT_Int)_height; + FT_Int char_width = bitmap->width; + FT_Int char_height = bitmap->rows; + + FT_Int x1 = CLAMP(x, 0, image_width); + FT_Int y1 = CLAMP(y, 0, image_height); + FT_Int x2 = CLAMP(x + char_width, 0, image_width); + FT_Int y2 = CLAMP(y + char_height, 0, image_height); + + FT_Int x_start = MAX(0, -x); + FT_Int y_offset = y1 - MAX(0, -y); + + for ( FT_Int i = y1; i < y2; ++i ) { + unsigned char* dst = _buffer + (i * image_width + x1); + unsigned char* src = bitmap->buffer + (((i - y_offset) * bitmap->pitch) + x_start); + for ( FT_Int j = x1; j < x2; ++j, ++dst, ++src ) + *dst |= *src; + } + + _isDirty = true; +} + +void FT2Image::write_bitmap(const char* filename) const { + FILE *fh = fopen(filename, "w"); + + for ( size_t i = 0; i< _height; i++) { + for ( size_t j = 0; j < _width; ++j) { + if (_buffer[j + i*_width]) + fputc('#', fh); + else + fputc(' ', fh); + } + fputc('\n', fh); + } + + fclose(fh); +} + +char FT2Image::write_bitmap__doc__[] = +"write_bitmap(fname)\n" +"\n" +"Write the bitmap to file fname\n" +; +Py::Object +FT2Image::py_write_bitmap(const Py::Tuple & args) { + _VERBOSE("FT2Image::write_bitmap"); + + args.verify_length(1); + + std::string filename = Py::String(args[0]); + + write_bitmap(filename.c_str()); + + return Py::Object(); +} + +void +FT2Image::draw_rect(unsigned long x0, unsigned long y0, + unsigned long x1, unsigned long y1) { + if ( x0<0 || y0<0 || x1<0 || y1<0 || + x0>_width || x1>_width || + y0>_height || y1>_height ) + throw Py::ValueError("Rect coords outside image bounds"); + + size_t top = y0*_width; + size_t bottom = y1*_width; + for (size_t i=x0; i<x1+1; ++i) { + _buffer[i + top] = 255; + _buffer[i + bottom] = 255; + } + + for (size_t j=y0+1; j<y1; ++j) { + _buffer[x0 + j*_width] = 255; + _buffer[x1 + j*_width] = 255; + } + + _isDirty = true; +} + +char FT2Image::draw_rect__doc__[] = +"draw_rect(x0, y0, x1, y1)\n" +"\n" +"Draw a rect to the image.\n" +"\n" +; +Py::Object +FT2Image::py_draw_rect(const Py::Tuple & args) { + _VERBOSE("FT2Image::draw_rect"); + + args.verify_length(4); + + long x0 = Py::Int(args[0]); + long y0 = Py::Int(args[1]); + long x1 = Py::Int(args[2]); + long y1 = Py::Int(args[3]); + + draw_rect(x0, y0, x1, y1); + + return Py::Object(); +} + +void FT2Image::draw_rect_filled(unsigned long x0, unsigned long y0, + unsigned long x1, unsigned long y1) { + x0 = CLAMP(x0, 0, _width); + y0 = CLAMP(y0, 0, _height); + x1 = CLAMP(x1, 0, _width); + y1 = CLAMP(y1, 0, _height); + + for (size_t j=y0; j<y1+1; j++) { + for (size_t i=x0; i<x1+1; i++) { + _buffer[i + j*_width] = 255; + } + } + + _isDirty = true; +} + +char FT2Image::draw_rect_filled__doc__[] = +"draw_rect_filled(x0, y0, x1, y1)\n" +"\n" +"Draw a filled rect to the image.\n" +"\n" +; +Py::Object +FT2Image::py_draw_rect_filled(const Py::Tuple & args) { + _VERBOSE("FT2Image::draw_rect_filled"); + + args.verify_length(4); + + long x0 = Py::Int(args[0]); + long y0 = Py::Int(args[1]); + long x1 = Py::Int(args[2]); + long y1 = Py::Int(args[3]); + + draw_rect_filled(x0, y0, x1, y1); + + return Py::Object(); +} + +char FT2Image::as_str__doc__[] = +"width, height, s = image_as_str()\n" +"\n" +"Return the image buffer as a string\n" +"\n" +; +Py::Object +FT2Image::py_as_str(const Py::Tuple & args) { + _VERBOSE("FT2Image::as_str"); + args.verify_length(0); + + return Py::asObject(PyString_FromStringAndSize((const char *)_buffer, _width*_height)); +} + +void FT2Image::makeRgbCopy() { + if (!_isDirty) + return; + + if (!_rgbCopy) { + _rgbCopy = new FT2Image(_width * 3, _height); + } else { + _rgbCopy->resize(_width * 3, _height); + } + unsigned char *src = _buffer; + unsigned char *src_end = src + (_width * _height); + unsigned char *dst = _rgbCopy->_buffer; + + unsigned char tmp; + while (src != src_end) { + tmp = 255 - *src++; + *dst++ = tmp; + *dst++ = tmp; + *dst++ = tmp; + } +} + +char FT2Image::as_rgb_str__doc__[] = +"width, height, s = image_as_rgb_str()\n" +"\n" +"Return the image buffer as a 24-bit RGB string.\n" +"\n" +; +Py::Object +FT2Image::py_as_rgb_str(const Py::Tuple & args) { + _VERBOSE("FT2Image::as_str_rgb"); + args.verify_length(0); + + makeRgbCopy(); + + return _rgbCopy->py_as_str(args); +} + +void FT2Image::makeRgbaCopy() { + if (!_isDirty) + return; + + if (!_rgbaCopy) { + _rgbaCopy = new FT2Image(_width * 4, _height); + } else { + _rgbaCopy->resize(_width * 4, _height); + } + unsigned char *src = _buffer; + unsigned char *src_end = src + (_width * _height); + unsigned char *dst = _rgbaCopy->_buffer; + + // This pre-multiplies the alpha, which apparently shouldn't + // be necessary for wxGTK, but it sure as heck seems to be. + unsigned int c; + unsigned int tmp; + while (src != src_end) { + c = *src++; + tmp = ((255 - c) * c) >> 8; + *dst++ = tmp; + *dst++ = tmp; + *dst++ = tmp; + *dst++ = c; + } +} + +char FT2Image::as_rgba_str__doc__[] = +"width, height, s = image_as_rgb_str()\n" +"\n" +"Return the image buffer as a 32-bit RGBA string.\n" +"\n" +; +Py::Object +FT2Image::py_as_rgba_str(const Py::Tuple & args) { + _VERBOSE("FT2Image::as_str_rgba"); + args.verify_length(0); + + makeRgbaCopy(); + + return _rgbaCopy->py_as_str(args); +} + +Py::Object +FT2Image::py_get_width(const Py::Tuple & args) { + _VERBOSE("FT2Image::get_width"); + args.verify_length(0); + + return Py::Int((long)get_width()); +} + +Py::Object +FT2Image::py_get_height(const Py::Tuple & args) { + _VERBOSE("FT2Image::get_height"); + args.verify_length(0); + + return Py::Int((long)get_height()); +} + Glyph::Glyph( const FT_Face& face, const FT_Glyph& glyph, size_t ind) : glyphInd(ind) { _VERBOSE("Glyph::Glyph"); @@ -105,7 +510,6 @@ //get the glyph as a path, a list of (COMMAND, *args) as desribed in matplotlib.path // this code is from agg's decompose_ft_outline with minor modifications - enum {MOVETO, LINETO, CURVE3, CURVE4, ENDPOLY}; FT_Outline& outline = face->glyph->outline; Py::List path; @@ -345,12 +749,12 @@ } -FT2Font::FT2Font(std::string facefile) +FT2Font::FT2Font(std::string facefile) : + image(NULL) { _VERBOSE(Printf("FT2Font::FT2Font %s", facefile.c_str()).str()); clear(Py::Tuple(0)); - int error = FT_New_Face( _ft2Library, facefile.c_str(), 0, &face ); @@ -447,75 +851,20 @@ FT2Font::~FT2Font() { _VERBOSE("FT2Font::~FT2Font"); + + if(image) + Py::_XDECREF(image); FT_Done_Face ( face ); - delete [] image.buffer ; - image.buffer = NULL; - for (size_t i=0; i<glyphs.size(); i++) { FT_Done_Glyph( glyphs[i] ); } + for (size_t i=0; i<gms.size(); i++) { Py_DECREF(gms[i]); } } - -char FT2Font::horiz_image_to_vert_image__doc__[] = -"horiz_image_to_vert_image()\n" -"\n" -"Copies the horizontal image (w, h) into a\n" -"new image of size (h,w)\n" -"This is equivalent to rotating the original image\n" -"by 90 degrees ccw\n" -; - -Py::Object -FT2Font::horiz_image_to_vert_image(const Py::Tuple & args) { - - // If we have already rotated, just return. - - if (image.bRotated) - return Py::Object(); - - - long width = image.width, height = image.height; - - long newWidth = image.height; - long newHeight = image.width; - - long numBytes = image.width * image.height; - - unsigned char * buffer = new unsigned char [numBytes]; - - long i, j, k, offset, nhMinusOne; - - nhMinusOne = newHeight-1; - - for (i=0; i<height; i++) { - - offset = i*width; - - for (j=0; j<width; j++) { - - k = nhMinusOne - j; - - buffer[i + k*newWidth] = image.buffer[j + offset]; - - } - - } - - delete [] image.buffer; - image.buffer = buffer; - image.width = newWidth; - image.height = newHeight; - image.bRotated = true; - - return Py::Object(); - -} - int FT2Font::setattr( const char *name, const Py::Object &value ) { _VERBOSE("FT2Font::setattr"); @@ -530,34 +879,6 @@ else return getattr_default( name ); } -char FT2Font::set_bitmap_size__doc__[] = -"set_bitmap_size(w, h)\n" -"\n" -"Manually set the bitmap size to render the glyps to. This is useful" -"in cases where you want to render several different glyphs to the bitmap" -; - -Py::Object -FT2Font::set_bitmap_size(const Py::Tuple & args) { - _VERBOSE("FT2Font::set_bitmap_size"); - args.verify_length(2); - - long width = Py::Int(args[0]); - long height = Py::Int(args[1]); - - image.width = (unsigned)width; - image.height = (unsigned)height; - - long numBytes = image.width * image.height; - - delete [] image.buffer; - image.buffer = new unsigned char [numBytes]; - for (long n=0; n<numBytes; n++) - image.buffer[n] = 0; - - return Py::Object(); -} - char FT2Font::clear__doc__[] = "clear()\n" "\n" @@ -569,13 +890,8 @@ _VERBOSE("FT2Font::clear"); args.verify_length(0); - //todo: move to image method? - delete [] image.buffer ; - image.buffer = NULL; - image.width = 0; - image.height = 0; - image.offsetx = 0; - image.offsety = 0; + if (image) + image->clear(); angle = 0.0; @@ -904,8 +1220,6 @@ _VERBOSE("FT2Font::get_width_height"); args.verify_length(0); - - FT_BBox bbox = compute_string_bbox(); Py::Tuple ret(2); @@ -930,152 +1244,6 @@ return Py::Int(- bbox.yMin);; } -void -FT2Font::draw_bitmap( FT_Bitmap* bitmap, - FT_Int x, - FT_Int y) { - _VERBOSE("FT2Font::draw_bitmap"); - FT_Int image_width = (FT_Int)image.width; - FT_Int image_height = (FT_Int)image.height; - FT_Int char_width = bitmap->width; - FT_Int char_height = bitmap->rows; - - FT_Int x1 = CLAMP(x, 0, image_width); - FT_Int y1 = CLAMP(y, 0, image_height); - FT_Int x2 = CLAMP(x + char_width, 0, image_width); - FT_Int y2 = CLAMP(y + char_height, 0, image_height); - - FT_Int x_start = MAX(0, -x); - FT_Int y_offset = y1 - MAX(0, -y); - - for ( FT_Int i = y1; i < y2; ++i ) { - unsigned char* dst = image.buffer + (i * image_width + x1); - unsigned char* src = bitmap->buffer + (((i - y_offset) * bitmap->pitch) + x_start); - for ( FT_Int j = x1; j < x2; ++j, ++dst, ++src ) - *dst |= *src; - } -} - -char FT2Font::write_bitmap__doc__[] = -"write_bitmap(fname)\n" -"\n" -"Write the bitmap to file fname\n" -; -Py::Object -FT2Font::write_bitmap(const Py::Tuple & args) { - _VERBOSE("FT2Font::write_bitmap"); - - args.verify_length(1); - - FT_Int i, j; - - std::string filename = Py::String(args[0]); - - FILE *fh = fopen(filename.c_str(), "w"); - FT_Int width = (FT_Int)image.width; - FT_Int height = (FT_Int)image.height; - - for ( i = 0; i< height; i++) - for ( j = 0; j < width; ++j) - fputc(image.buffer[j + i*width], fh); - - fclose(fh); - - return Py::Object(); -} - -char FT2Font::draw_rect__doc__[] = -"draw_rect(x0, y0, x1, y1)\n" -"\n" -"Draw a rect to the image. It is your responsibility to set the dimensions\n" -"of the image, eg, with set_bitmap_size\n" -"\n" -; -Py::Object -FT2Font::draw_rect(const Py::Tuple & args) { - _VERBOSE("FT2Font::draw_rect"); - - args.verify_length(4); - - long x0 = Py::Int(args[0]); - long y0 = Py::Int(args[1]); - long x1 = Py::Int(args[2]); - long y1 = Py::Int(args[3]); - - FT_Int iwidth = (FT_Int)image.width; - FT_Int iheight = (FT_Int)image.height; - - if ( x0<0 || y0<0 || x1<0 || y1<0 || - x0>iwidth || x1>iwidth || - y0>iheight || y1>iheight ) - throw Py::ValueError("Rect coords outside image bounds"); - - for (long i=x0; i<x1+1; ++i) { - image.buffer[i + y0*iwidth] = 255; - image.buffer[i + y1*iwidth] = 255; - } - - for (long j=y0+1; j<y1; ++j) { - image.buffer[x0 + j*iwidth] = 255; - image.buffer[x1 + j*iwidth] = 255; - } - return Py::Object(); -} - -char FT2Font::draw_rect_filled__doc__[] = -"draw_rect_filled(x0, y0, x1, y1)\n" -"\n" -"Draw a filled rect to the image. It is your responsibility to set the\n" -"dimensions of the image, eg, with set_bitmap_size\n" -"\n" -; -Py::Object -FT2Font::draw_rect_filled(const Py::Tuple & args) { - _VERBOSE("FT2Font::draw_rect_filled"); - - args.verify_length(4); - - long x0 = Py::Int(args[0]); - long y0 = Py::Int(args[1]); - long x1 = Py::Int(args[2]); - long y1 = Py::Int(args[3]); - - FT_Int iwidth = (FT_Int)image.width; - FT_Int iheight = (FT_Int)image.height; - - x0 = CLAMP(x0, 0, iwidth); - y0 = CLAMP(y0, 0, iheight); - x1 = CLAMP(x1, 0, iwidth); - y1 = CLAMP(y1, 0, iheight); - - for (long j=y0; j<y1+1; j++) { - for (long i=x0; i<x1+1; i++) { - image.buffer[i + j*iwidth] = 255; - } - } - return Py::Object(); -} - -char FT2Font::image_as_str__doc__[] = -"width, height, s = image_as_str()\n" -"\n" -"Return the image buffer as a string\n" -"\n" -; -Py::Object -FT2Font::image_as_str(const Py::Tuple & args) { - _VERBOSE("FT2Font::image_as_str"); - args.verify_length(0); - - return Py::asObject( - Py_BuildValue("lls#", - image.width, - image.height, - image.buffer, - image.width*image.height) - ); -} - char FT2Font::draw_glyphs_to_bitmap__doc__[] = "draw_glyphs_to_bitmap()\n" "\n" @@ -1089,22 +1257,21 @@ args.verify_length(0); FT_BBox string_bbox = compute_string_bbox(); + size_t width = (string_bbox.xMax-string_bbox.xMin) / 64 + 2; + size_t height = (string_bbox.yMax-string_bbox.yMin) / 64 + 2; - image.width = (string_bbox.xMax-string_bbox.xMin) / 64 + 2; - image.height = (string_bbox.yMax-string_bbox.yMin) / 64 + 2; + if (!image) { + image = new FT2Image(width, height); + } else { + image->resize(width, height); + } - image.offsetx = (int)(string_bbox.xMin / 64.0); + image->offsetx = (int)(string_bbox.xMin / 64.0); if (angle==0) - image.offsety = -image.height; + image->offsety = -image->get_height(); else - image.offsety = (int)(-string_bbox.yMax/64.0); + image->offsety = (int)(-string_bbox.yMax/64.0); - size_t numBytes = image.width*image.height; - delete [] image.buffer; - image.buffer = new unsigned char [numBytes]; - for (size_t n=0; n<numBytes; n++) - image.buffer[n] = 0; - for ( size_t n = 0; n < glyphs.size(); n++ ) { FT_BBox bbox; @@ -1113,8 +1280,7 @@ error = FT_Glyph_To_Bitmap(&glyphs[n], ft_render_mode_normal, 0, - //&pos[n], - 1 //destroy image; + 1 ); if (error) throw Py::RuntimeError("Could not convert glyph to bitmap"); @@ -1126,7 +1292,7 @@ FT_Int x = (FT_Int)(bitmap->left - (string_bbox.xMin / 64.)); FT_Int y = (FT_Int)((string_bbox.yMax / 64.) - bitmap->top + 1); - draw_bitmap( &bitmap->bitmap, x, y); + image->draw_bitmap( &bitmap->bitmap, x, y); } return Py::Object(); @@ -1156,8 +1322,7 @@ error = FT_Glyph_To_Bitmap(&glyphs[n], ft_render_mode_normal, 0, - //&pos[n], - 1 //destroy image; + 1 ); if (error) throw Py::RuntimeError("Could not convert glyph to bitmap"); @@ -1181,7 +1346,7 @@ } char FT2Font::draw_glyph_to_bitmap__doc__[] = -"draw_glyph_to_bitmap(x, y, glyph)\n" +"draw_glyph_to_bitmap(bitmap, x, y, glyph)\n" "\n" "Draw a single glyph to the bitmap at pixel locations x,y\n" "Note it is your responsibility to set up the bitmap manually\n" @@ -1195,16 +1360,17 @@ Py::Object FT2Font::draw_glyph_to_bitmap(const Py::Tuple & args) { _VERBOSE("FT2Font::draw_glyph_to_bitmap"); - args.verify_length(3); + args.verify_length(4); - if (image.width==0 || image.height==0) - throw Py::RuntimeError("You must first set the size of the bitmap with set_bitmap_size"); + if (!FT2Image::check(args[0].ptr())) + throw Py::TypeError("Usage: draw_glyph_to_bitmap(bitmap, x,y,glyph)"); + FT2Image* im = static_cast<FT2Image*>(args[0].ptr()); - long x = Py::Int(args[0]); - long y = Py::Int(args[1]); - if (!Glyph::check(args[2].ptr())) - throw Py::TypeError("Usage: draw_glyph_to_bitmap(x,y,glyph)"); - Glyph* glyph = static_cast<Glyph*>(args[2].ptr()); + long x = Py::Int(args[1]); + long y = Py::Int(args[2]); + if (!Glyph::check(args[3].ptr())) + throw Py::TypeError("Usage: draw_glyph_to_bitmap(bitmap, x,y,glyph)"); + Glyph* glyph = static_cast<Glyph*>(args[3].ptr()); if ((size_t)glyph->glyphInd >= glyphs.size()) throw Py::ValueError("glyph num is out of range"); @@ -1219,7 +1385,7 @@ FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[glyph->glyphInd]; - draw_bitmap( &bitmap->bitmap, x + bitmap->left, y); + im->draw_bitmap( &bitmap->bitmap, x + bitmap->left, y); return Py::Object(); } @@ -1611,7 +1777,28 @@ } } +char FT2Font::get_image__doc__ [] = + "get_image()\n" + "\n" + "Returns the underlying image buffer for this font object.\n"; Py::Object +FT2Font::get_image (const Py::Tuple &args) { + args.verify_length(0); + Py_INCREF(image); + return Py::asObject(image); +} + +Py::Object +ft2font_module::new_ft2image (const Py::Tuple &args) { + args.verify_length(2); + + int width = Py::Int(args[0]); + int height = Py::Int(args[1]); + + return Py::asObject( new FT2Image(width, height) ); +} + +Py::Object ft2font_module::new_ft2font (const Py::Tuple &args) { _VERBOSE("ft2font_module::new_ft2font "); args.verify_length(1); @@ -1621,6 +1808,36 @@ } void +FT2Image::init_type() { + _VERBOSE("FT2Image::init_type"); + behaviors().name("FT2Image"); + behaviors().doc("FT2Image"); + + add_varargs_method("clear", &FT2Image::py_clear, + FT2Image::clear__doc__); + add_varargs_method("resize", &FT2Image::py_resize, + FT2Image::resize__doc__); + add_varargs_method("rotate", &FT2Image::py_rotate, + FT2Image::rotate__doc__); + add_varargs_method("write_bitmap", &FT2Image::py_write_bitmap, + FT2Image::write_bitmap__doc__); + add_varargs_method("draw_rect", &FT2Image::py_draw_rect, + FT2Image::draw_rect__doc__); + add_varargs_method("draw_rect_filled", &FT2Image::py_draw_rect_filled, + FT2Image::draw_rect_filled__doc__); + add_varargs_method("as_str", &FT2Image::py_as_str, + FT2Image::as_str__doc__); + add_varargs_method("as_rgb_str", &FT2Image::py_as_rgb_str, + FT2Image::as_rgb_str__doc__); + add_varargs_method("as_rgba_str", &FT2Image::py_as_rgba_str, + FT2Image::as_rgba_str__doc__); + add_varargs_method("get_width", &FT2Image::py_get_width, + "Returns the width of the image"); + add_varargs_method("get_height", &FT2Image::py_get_height, + "Returns the height of the image"); +} + +void Glyph::init_type() { _VERBOSE("Glyph::init_type"); behaviors().name("Glyph"); @@ -1637,14 +1854,6 @@ add_varargs_method("clear", &FT2Font::clear, FT2Font::clear__doc__); - add_varargs_method("write_bitmap", &FT2Font::write_bitmap, - FT2Font::write_bitmap__doc__); - add_varargs_method("set_bitmap_size", &FT2Font::set_bitmap_size, - FT2Font::load_char__doc__); - add_varargs_method("draw_rect",&FT2Font::draw_rect, - FT2Font::draw_rect__doc__); - add_varargs_method("draw_rect_filled",&FT2Font::draw_rect_filled, - FT2Font::draw_rect_filled__doc__); add_varargs_method("draw_glyph_to_bitmap", &FT2Font::draw_glyph_to_bitmap, FT2Font::draw_glyph_to_bitmap__doc__); add_varargs_method("draw_glyphs_to_bitmap", &FT2Font::draw_glyphs_to_bitmap, @@ -1656,8 +1865,6 @@ FT2Font::get_glyph__doc__); add_varargs_method("get_num_glyphs", &FT2Font::get_num_glyphs, FT2Font::get_num_glyphs__doc__); - add_varargs_method("image_as_str", &FT2Font::image_as_str, - FT2Font::image_as_str__doc__); add_keyword_method("load_char", &FT2Font::load_char, FT2Font::load_char__doc__); add_keyword_method("set_text", &FT2Font::set_text, @@ -1685,9 +1892,8 @@ FT2Font::get_ps_font_info__doc__); add_varargs_method("get_sfnt_table", &FT2Font::get_sfnt_table, FT2Font::get_sfnt_table__doc__); - add_varargs_method("horiz_image_to_vert_image", - &FT2Font::horiz_image_to_vert_image, - FT2Font::horiz_image_to_vert_image__doc__); + add_varargs_method("get_image", &FT2Font::get_image, + FT2Font::get_image__doc__); behaviors().supportGetattr(); behaviors().supportSetattr(); Modified: trunk/matplotlib/src/ft2font.h =================================================================== --- trunk/matplotlib/src/ft2font.h 2007-08-31 17:23:32 UTC (rev 3763) +++ trunk/matplotlib/src/ft2font.h 2007-08-31 19:25:17 UTC (rev 3764) @@ -20,15 +20,64 @@ // the freetype string rendered into a width, height buffer -class FT2Image { +class FT2Image : public Py::PythonExtension<FT2Image> { public: FT2Image(); + FT2Image(unsigned long width, unsigned long height); ~FT2Image(); - bool bRotated; - unsigned char *buffer; - unsigned long width; - unsigned long height; - int offsetx, offsety; + + static void init_type(); + + void resize(unsigned long width, unsigned long height); + void clear(); + void rotate(); + void draw_bitmap(FT_Bitmap* bitmap, FT_Int x, FT_Int y); + void write_bitmap(const char* filename) const; + void draw_rect(unsigned long x0, unsigned long y0, + unsigned long x1, unsigned long y1); + void draw_rect_filled(unsigned long x0, unsigned long y0, + unsigned long x1, unsigned long y1); + + unsigned int get_width() const { return _width; }; + unsigned int get_height() const { return _height; }; + const unsigned char *const get_buffer() const { return _buffer; }; + + static char clear__doc__ []; + Py::Object py_clear(const Py::Tuple & args); + static char resize__doc__ []; + Py::Object py_resize(const Py::Tuple & args); + static char rotate__doc__ []; + Py::Object py_rotate(const Py::Tuple & args); + static char write_bitmap__doc__ []; + Py::Object py_write_bitmap(const Py::Tuple & args); + static char draw_rect__doc__ []; + Py::Object py_draw_rect(const Py::Tuple & args); + static char draw_rect_filled__doc__ []; + Py::Object py_draw_rect_filled(const Py::Tuple & args); + static char as_str__doc__ []; + Py::Object py_as_str(const Py::Tuple & args); + static char as_rgb_str__doc__ []; + Py::Object py_as_rgb_str(const Py::Tuple & args); + static char as_rgba_str__doc__ []; + Py::Object py_as_rgba_str(const Py::Tuple & args); + + Py::Object py_get_width(const Py::Tuple & args); + Py::Object py_get_height(const Py::Tuple & args); + + unsigned long offsetx; + unsigned long offsety; + + private: + bool _bRotated; + bool _isDirty; + unsigned char *_buffer; + unsigned long _width; + unsigned long _height; + FT2Image* _rgbCopy; + FT2Image* _rgbaCopy; + + void makeRgbCopy(); + void makeRgbaCopy(); }; @@ -52,7 +101,6 @@ FT2Font(std::string); ~FT2Font(); static void init_type(void); - Py::Object set_bitmap_size(const Py::Tuple & args); Py::Object clear(const Py::Tuple & args); Py::Object set_size(const Py::Tuple & args); Py::Object set_charmap(const Py::Tuple & args); @@ -63,10 +111,7 @@ Py::Object load_char(const Py::Tuple & args, const Py::Dict & kws); Py::Object get_width_height(const Py::Tuple & args); Py::Object get_descent(const Py::Tuple & args); - Py::Object write_bitmap(const Py::Tuple & args); - Py::Object draw_rect(const Py::Tuple & args); Py::Object draw_rect_filled(const Py::Tuple & args); - Py::Object image_as_str(const Py::Tuple & args); Py::Object get_xys(const Py::Tuple & args); Py::Object draw_glyphs_to_bitmap(const Py::Tuple & args); Py::Object draw_glyph_to_bitmap(const Py::Tuple & args); @@ -76,10 +121,10 @@ Py::Object get_name_index(const Py::Tuple & args); Py::Object get_ps_font_info(const Py::Tuple & args); Py::Object get_sfnt_table(const Py::Tuple & args); - Py::Object horiz_image_to_vert_image(const Py::Tuple & args); + Py::Object get_image(const Py::Tuple & args); int setattr( const char *_name, const Py::Object &value ); Py::Object getattr( const char *_name ); - FT2Image image; + FT2Image* image; private: Py::Dict __dict__; @@ -96,10 +141,8 @@ FT_BBox compute_string_bbox(); - void draw_bitmap( FT_Bitmap* bitmap, FT_Int x, FT_Int y); void set_scalable_attributes(); - static char set_bitmap_size__doc__ []; static char clear__doc__ []; static char set_size__doc__ []; static char set_charmap__doc__ []; @@ -110,10 +153,6 @@ static char get_width_height__doc__ []; static char get_descent__doc__ []; static char get_kerning__doc__ []; - static char write_bitmap__doc__ []; - static char draw_rect__doc__ []; - static char draw_rect_filled__doc__ []; - static char image_as_str__doc__ []; static char draw_glyphs_to_bitmap__doc__ []; static char get_xys__doc__ []; static char draw_glyph_to_bitmap__doc__ []; @@ -123,7 +162,7 @@ static char get_name_index__doc__[]; static char get_ps_font_info__doc__[]; static char get_sfnt_table__doc__[]; - static char horiz_image_to_vert_image__doc__[]; + static char get_image__doc__[]; }; // the extension module @@ -134,11 +173,14 @@ ft2font_module() : Py::ExtensionModule<ft2font_module>( "ft2font" ) { + FT2Image::init_type(); Glyph::init_type(); FT2Font::init_type(); add_varargs_method("FT2Font", &ft2font_module::new_ft2font, "FT2Font"); + add_varargs_method("FT2Image", &ft2font_module::new_ft2image, + "FT2Image"); initialize( "The ft2font module" ); } @@ -148,6 +190,7 @@ private: Py::Object new_ft2font (const Py::Tuple &args); + Py::Object new_ft2image (const Py::Tuple &args); }; Modified: trunk/matplotlib/unit/agg_memleak.py =================================================================== --- trunk/matplotlib/unit/agg_memleak.py 2007-08-31 17:23:32 UTC (rev 3763) +++ trunk/matplotlib/unit/agg_memleak.py 2007-08-31 19:25:17 UTC (rev 3764) @@ -41,7 +41,7 @@ font.clear() font.set_text('hi mom', 60) font.set_size(12, 72) - o.draw_text( font, 30, 40, gc) + o.draw_text_image(font.get_image(), 30, 40, gc) o.write_png('aggtest%d.png'%i) val = report_memory(i) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jo...@us...> - 2007-09-03 21:36:32
|
Revision: 3770 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3770&view=rev Author: jouni Date: 2007-09-03 14:36:17 -0700 (Mon, 03 Sep 2007) Log Message: ----------- Created new file type1font.py for supporting Type 1 fonts; quite preliminary for now. Started adding Type 1 support to PDF backend for purposes of usetex. Modified Paths: -------------- trunk/matplotlib/API_CHANGES trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/afm.py trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py trunk/matplotlib/lib/matplotlib/dviread.py trunk/matplotlib/src/ft2font.cpp trunk/matplotlib/src/ft2font.h Added Paths: ----------- trunk/matplotlib/lib/matplotlib/type1font.py Modified: trunk/matplotlib/API_CHANGES =================================================================== --- trunk/matplotlib/API_CHANGES 2007-09-03 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/API_CHANGES 2007-09-03 21:36:17 UTC (rev 3770) @@ -1,3 +1,18 @@ + The dviread.py file now has a parser for files like psfonts.map + and pdftex.map, to map TeX font names to external files. + + The file type1font.py contains a new class for Type 1 fonts. + Currently it simply reads pfa and pfb format files and stores the + data in pfa format, which is the format for embedding Type 1 fonts + in postscript and pdf files. In the future the class might + actually parse the font to allow e.g. subsetting. + + FT2Font now supports FT_Attach_File. In practice this can be used + to read an afm file in addition to a pfa/pfb file, to get metrics + and kerning information for a Type 1 font. + + The AFM class now supports querying CapHeight and stem widths. + Changed pcolor default to shading='flat'; but as noted now in the docstring, it is preferable to simply use the edgecolor kwarg. Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2007-09-03 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/CHANGELOG 2007-09-03 21:36:17 UTC (rev 3770) @@ -1,3 +1,9 @@ +2007-09-03 Created type1font.py, added features to AFM and FT2Font + (see API_CHANGES), started work on embedding Type 1 fonts + in pdf files. - JKS + +2007-09-02 Continued work on dviread.py. - JKS + 2007-08-16 Added a set_extent method to AxesImage, allow data extent to be modified after initial call to imshow - DSD Modified: trunk/matplotlib/lib/matplotlib/afm.py =================================================================== --- trunk/matplotlib/lib/matplotlib/afm.py 2007-09-03 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/lib/matplotlib/afm.py 2007-09-03 21:36:17 UTC (rev 3770) @@ -103,7 +103,8 @@ 'Version': _to_str, 'Notice': _to_str, 'EncodingScheme': _to_str, - 'CapHeight': _to_float, + 'CapHeight': _to_float, # Is the second version a mistake, or + 'Capheight': _to_float, # do some AFM files contain 'Capheight'? -JKS 'XHeight': _to_float, 'Ascender': _to_float, 'Descender': _to_float, @@ -112,7 +113,6 @@ 'StartCharMetrics': _to_int, 'CharacterSet': _to_str, 'Characters': _to_int, - 'Capheight': _to_int, } d = {} @@ -446,6 +446,10 @@ "Return the fontangle as float" return self._header['ItalicAngle'] + def get_capheight(self): + "Return the cap height as float" + return self._header['CapHeight'] + def get_xheight(self): "Return the xheight as float" return self._header['XHeight'] @@ -453,6 +457,20 @@ def get_underline_thickness(self): "Return the underline thickness as float" return self._header['UnderlineThickness'] + + def get_horizontal_stem_width(self): + """ + Return the standard horizontal stem width as float, or None if + not specified in AFM file. + """ + return self._header.get('StdHW', None) + + def get_vertical_stem_width(self): + """ + Return the standard vertical stem width as float, or None if + not specified in AFM file. + """ + return self._header.get('StdVW', None) if __name__=='__main__': Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-09-03 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-09-03 21:36:17 UTC (rev 3770) @@ -26,7 +26,8 @@ from matplotlib.figure import Figure from matplotlib.font_manager import findfont from matplotlib.afm import AFM -from matplotlib.dviread import Dvi +import matplotlib.type1font as type1font +import matplotlib.dviread as dviread from matplotlib.ft2font import FT2Font, FIXED_WIDTH, ITALIC, LOAD_NO_SCALE, \ LOAD_NO_HINTING, KERNING_UNFITTED from matplotlib.mathtext import MathTextParser @@ -367,6 +368,7 @@ # self.fontNames maps filenames to internal font names self.fontNames = {} self.nextFont = 1 # next free internal font name + self.fontInfo = {} # information on fonts: metrics, encoding self.alphaStates = {} # maps alpha values to graphics state objects self.nextAlphaState = 1 @@ -438,6 +440,12 @@ self.currentstream = None def fontName(self, fontprop): + """ + Select a font based on fontprop and return a name suitable for + Op.selectfont. If fontprop is a string, it will be interpreted + as the filename of the font. + """ + if is_string_like(fontprop): filename = fontprop elif rcParams['pdf.use14corefonts']: @@ -458,6 +466,9 @@ for filename, Fx in self.fontNames.items(): if filename.endswith('.afm'): fontdictObject = self._write_afm_font(filename) + elif filename.endswith('.pfb') or filename.endswith('.pfa'): + # a Type 1 font; limited support for now + fontdictObject = self.embedType1(filename, self.fontInfo[Fx]) else: realpath, stat_key = get_realpath_and_stat(filename) chars = self.used_characters.get(stat_key) @@ -480,6 +491,97 @@ self.writeObject(fontdictObject, fontdict) return fontdictObject + def embedType1(self, filename, fontinfo): + fh = open(filename, 'rb') + try: + fontdata = fh.read() + finally: + fh.close() + + fh = open(fontinfo.afmfile, 'rb') + try: + afmdata = AFM(fh) + finally: + fh.close() + + font = FT2Font(filename) + font.attach_file(fontinfo.afmfile) + + widthsObject, fontdescObject, fontdictObject, fontfileObject = \ + [ self.reserveObject(n) for n in + ('font widths', 'font descriptor', + 'font dictionary', 'font file') ] + + _, _, fullname, familyname, weight, italic_angle, fixed_pitch, \ + ul_position, ul_thickness = font.get_ps_font_info() + + differencesArray = [ 0 ] + [ Name(ch) for ch in + dviread.Encoding(fontinfo.encoding) ] + + fontdict = { + 'Type': Name('Font'), + 'Subtype': Name('Type1'), + 'BaseFont': Name(font.postscript_name), + 'FirstChar': 0, + 'LastChar': len(differencesArray) - 2, + 'Widths': widthsObject, + 'FontDescriptor': fontdescObject, + 'Encoding': { 'Type': Name('Encoding'), + 'Differences': differencesArray }, + } + + flags = 0 + if fixed_pitch: flags |= 1 << 0 # fixed width + if 0: flags |= 1 << 1 # TODO: serif + if 0: flags |= 1 << 2 # TODO: symbolic + else: flags |= 1 << 5 # non-symbolic + if italic_angle: flags |= 1 << 6 # italic + if 0: flags |= 1 << 16 # TODO: all caps + if 0: flags |= 1 << 17 # TODO: small caps + if 0: flags |= 1 << 18 # TODO: force bold + + descriptor = { + 'Type': Name('FontDescriptor'), + 'FontName': Name(font.postscript_name), + 'Flags': flags, + 'FontBBox': font.bbox, + 'ItalicAngle': italic_angle, + 'Ascent': font.ascender, + 'Descent': font.descender, + 'CapHeight': afmdata.get_capheight(), + 'XHeight': afmdata.get_xheight(), + 'FontFile': fontfileObject, + 'FontFamily': Name(familyname), + #'FontWeight': a number where 400 = Regular, 700 = Bold + } + + # StemV is obligatory in PDF font descriptors but optional in + # AFM files. The collection of AFM files in my TeX Live 2007 + # collection has values ranging from 22 to 219, with both + # median and mode 50, so if the AFM file is silent, I'm + # guessing 50. -JKS + StemV = afmdata.get_vertical_stem_width() + if StemV is None: StemV = 50 + descriptor['StemV'] = StemV + + # StemH is entirely optional: + StemH = afmdata.get_horizontal_stem_width() + if StemH is not None: + descriptor['StemH'] = StemH + + self.writeObject(fontdictObject, fontdict) + self.writeObject(widthsObject, widths) + self.writeObject(fontdescObject, descriptor) + + fontdata = type1font.Type1Font(filename) + len1, len2, len3 = fontdata.lenghts() + self.beginStream(fontfileObject.id, None, + { 'Length1': len1, + 'Length2': len2, + 'Length3': len3 }) + self.currentstream.write(fontdata.data) + self.endStream() + def _get_xobject_symbol_name(self, filename, symbol_name): return "%s-%s" % ( os.path.splitext(os.path.basename(filename))[0], @@ -1034,6 +1136,7 @@ self.encode_string = self.encode_string_type42 self.mathtext_parser = MathTextParser("Pdf") self.image_magnification = dpi/72.0 + self.tex_font_map = None def finalize(self): self.gc.finalize() @@ -1050,6 +1153,12 @@ # Restore gc to avoid unwanted side effects gc._fillcolor = orig_fill + def tex_font_mapping(self, texfont): + if self.tex_font_map is None: + self.tex_font_map = \ + dviread.PsfontsMap(dviread.find_tex_file('pdftex.map')) + return self.tex_font_map[texfont] + def track_characters(self, font, s): """Keeps track of which characters are required from each font.""" @@ -1288,9 +1397,8 @@ texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() dvifile = texmanager.make_dvi(s, fontsize) - dvi = Dvi(dvifile, 72) + dvi = dviread.Dvi(dvifile, 72) text, boxes = iter(dvi).next() - fontdir = os.path.join(get_data_path(), 'fonts', 'ttf') if angle == 0: # avoid rounding errors in common case def mytrans(x1, y1): @@ -1303,14 +1411,17 @@ self.check_gc(gc, gc._rgb) self.file.output(Op.begin_text) - oldfont, oldx, oldy = None, 0, 0 - for x1, y1, font, glyph in text: - if font != oldfont: - fontname, fontsize = dvi.fontinfo(font) - fontfile = os.path.join(fontdir, fontname+'.ttf') - self.file.output(self.file.fontName(fontfile), - fontsize, Op.selectfont) - oldfont = font + oldfontnum, oldx, oldy = None, 0, 0 + for x1, y1, fontnum, glyph in text: + if fontnum != oldfontnum: + texname, fontsize = dvi.fontinfo(fontnum) + fontinfo = self.tex_font_mapping(texname) + pdfname = self.file.fontName(fontinfo.filename) + self.file.fontInfo[pdfname] = Bunch( + encodingfile=fontinfo.encoding, + afmfile=fontinfo.afm) + self.file.output(pdfname, fontsize, Op.selectfont) + oldfontnum = fontnum x1, y1 = mytrans(x1, y1) self._setup_textpos(x1, y1, angle, oldx, oldy) self.file.output(chr(glyph), Op.show) Modified: trunk/matplotlib/lib/matplotlib/dviread.py =================================================================== --- trunk/matplotlib/lib/matplotlib/dviread.py 2007-09-03 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/lib/matplotlib/dviread.py 2007-09-03 21:36:17 UTC (rev 3770) @@ -410,11 +410,11 @@ def __getitem__(self, texname): result = self._font[texname] - if result.filename is not None \ - and not result.filename.startswith('/'): - result.filename = find_tex_file(result.filename) - if result.encoding is not None \ - and not result.encoding.startswith('/'): + fn, enc = result.filename, result.encoding + if fn is not None and not fn.startswith('/'): + result.filename = find_tex_file(fn) + result.afm = find_tex_file(fn[:-4] + '.afm') + if enc is not None and not enc.startswith('/'): result.encoding = find_tex_file(result.encoding) return result @@ -473,6 +473,51 @@ texname=texname, psname=psname, effects=effects, encoding=encoding, filename=filename) +class Encoding(object): + + def __init__(self, filename): + file = open(filename, 'rt') + try: + self.encoding = self._parse(file) + finally: + file.close() + + def __iter__(self): + for name in self.encoding: + yield name + + def _parse(self, file): + result = [] + + state = 0 + for line in file: + comment_start = line.find('%') + if comment_start > -1: + line = line[:comment_start] + line = line.strip() + + if state == 0: + # Expecting something like /FooEncoding [ + if '[' in line: + state = 1 + line = line[line.index('[')+1].strip() + + if state == 1: + words = line.split() + for w in words: + if w.startswith('/'): + # Allow for /abc/def/ghi + subwords = w.split('/') + result.extend(subwords[1:]) + else: + raise ValueError, "Broken name in encoding file: " + w + + # Expecting ] def + if ']' in line: + break + + return result + def find_tex_file(filename, format=None): """ Call kpsewhich to find a file in the texmf tree. Added: trunk/matplotlib/lib/matplotlib/type1font.py =================================================================== --- trunk/matplotlib/lib/matplotlib/type1font.py (rev 0) +++ trunk/matplotlib/lib/matplotlib/type1font.py 2007-09-03 21:36:17 UTC (rev 3770) @@ -0,0 +1,95 @@ +""" +A class representing a Type 1 font. + +This version merely allows reading in pfa and pfb files, and stores +the data in pfa format (which can be embedded in PostScript or PDF +files). A more complete class might support subsetting. + +Usage: font = Type1Font(filename) + somefile.write(font.data) # writes out font in pfa format + len1, len2, len3 = font.lengths() # needed for pdf embedding + +Source: Adobe Technical Note #5040, Supporting Downloadable PostScript +Language Fonts. + +If extending this class, see also: Adobe Type 1 Font Format, Adobe +Systems Incorporated, third printing, v1.1, 1993. ISBN 0-201-57044-0. +""" + +import struct + +class Type1Font(object): + + def __init__(self, filename): + file = open(filename, 'rb') + try: + self._read(file) + finally: + file.close() + + def _read(self, file): + rawdata = file.read() + if not rawdata.startswith(chr(128)): + self.data = rawdata + return + + self.data = '' + while len(rawdata) > 0: + if not rawdata.startswith(chr(128)): + raise RuntimeError, \ + 'Broken pfb file (expected byte 128, got %d)' % \ + ord(rawdata[0]) + type = ord(rawdata[1]) + if type in (1,2): + length, = struct.unpack('<i', rawdata[2:6]) + segment = rawdata[6:6+length] + rawdata = rawdata[6+length:] + + if type == 1: # ASCII text: include verbatim + self.data += segment + elif type == 2: # binary data: encode in hexadecimal + self.data += ''.join(['%02x' % ord(char) + for char in segment]) + elif type == 3: # end of file + break + else: + raise RuntimeError, \ + 'Unknown segment type %d in pfb file' % type + + def lengths(self): + """ + Compute the lengths of the three parts of a Type 1 font. + + The three parts are: (1) the cleartext part, which ends in a + eexec operator; (2) the encrypted part; (3) the fixed part, + which contains 512 ASCII zeros possibly divided on various + lines, a cleartomark operator, and possibly something else. + """ + + # Cleartext part: just find the eexec and skip the eol char(s) + idx = self.data.index('eexec') + idx += len('eexec') + while self.data[idx] in ('\n', '\r'): + idx += 1 + len1 = idx + + # Encrypted part: find the cleartomark operator and count + # zeros backward + idx = self.data.rindex('cleartomark') - 1 + zeros = 512 + while zeros and self.data[idx] in ('0', '\n', '\r'): + if self.data[idx] == '0': + zeros -= 1 + idx -= 1 + if zeros: + raise RuntimeError, 'Insufficiently many zeros in Type 1 font' + + len2 = idx - len1 + len3 = len(self.data) - idx + + return len1, len2, len3 + +if __name__ == '__main__': + import sys + font = Type1Font(sys.argv[1]) + sys.stdout.write(font.data) Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007-09-03 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/src/ft2font.cpp 2007-09-03 21:36:17 UTC (rev 3770) @@ -1552,11 +1552,11 @@ } Py::Tuple info(9); - info[0] = Py::String(fontinfo.version); - info[1] = Py::String(fontinfo.notice); - info[2] = Py::String(fontinfo.full_name); - info[3] = Py::String(fontinfo.family_name); - info[4] = Py::String(fontinfo.weight); + info[0] = Py::String(fontinfo.version ? fontinfo.version : ""); + info[1] = Py::String(fontinfo.notice ? fontinfo.notice : ""); + info[2] = Py::String(fontinfo.full_name ? fontinfo.full_name : ""); + info[3] = Py::String(fontinfo.family_name ? fontinfo.family_name : ""); + info[4] = Py::String(fontinfo.weight ? fontinfo.weight : ""); info[5] = Py::Long(fontinfo.italic_angle); info[6] = Py::Int(fontinfo.is_fixed_pitch); info[7] = Py::Int(fontinfo.underline_position); @@ -1788,7 +1788,30 @@ return Py::asObject(image); } +char FT2Font::attach_file__doc__ [] = + "attach_file(filename)\n" + "\n" + "Attach a file with extra information on the font\n" + "(in practice, an AFM file with the metrics of a Type 1 font).\n" + "Throws an exception if unsuccessful.\n"; Py::Object +FT2Font::attach_file (const Py::Tuple &args) { + args.verify_length(1); + + std::string filename = Py::String(args[0]); + FT_Error error = + FT_Attach_File(face, filename.c_str()); + + if (error) { + std::ostringstream s; + s << "Could not attach file " << filename + << " (freetype error code " << error << ")" << std::endl; + throw Py::RuntimeError(s.str()); + } + return Py::Object(); +} + +Py::Object ft2font_module::new_ft2image (const Py::Tuple &args) { args.verify_length(2); @@ -1894,6 +1917,8 @@ FT2Font::get_sfnt_table__doc__); add_varargs_method("get_image", &FT2Font::get_image, FT2Font::get_image__doc__); + add_varargs_method("attach_file", &FT2Font::attach_file, + FT2Font::attach_file__doc__); behaviors().supportGetattr(); behaviors().supportSetattr(); @@ -1949,6 +1974,7 @@ " max_advance_height same for vertical layout\n" " underline_position vertical position of the underline bar\n" " underline_thickness vertical thickness of the underline\n" +" postscript_name PostScript name of the font\n" ; #if defined(_MSC_VER) Modified: trunk/matplotlib/src/ft2font.h =================================================================== --- trunk/matplotlib/src/ft2font.h 2007-09-03 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/src/ft2font.h 2007-09-03 21:36:17 UTC (rev 3770) @@ -122,6 +122,7 @@ Py::Object get_ps_font_info(const Py::Tuple & args); Py::Object get_sfnt_table(const Py::Tuple & args); Py::Object get_image(const Py::Tuple & args); + Py::Object attach_file(const Py::Tuple & args); int setattr( const char *_name, const Py::Object &value ); Py::Object getattr( const char *_name ); FT2Image* image; @@ -163,6 +164,7 @@ static char get_ps_font_info__doc__[]; static char get_sfnt_table__doc__[]; static char get_image__doc__[]; + static char attach_file__doc__[]; }; // the extension module This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |