Project: matplotlib
Code Location: git://
Download File
Script to autogenerate pyplot wrappers.

When this script is run, the current contents of pyplot are
split into generatable and non-generatable content (via the magic header
:attr:`PYPLOT_MAGIC_HEADER`) and the generatable content is overwritten.
Hence, the non-generatable content should be edited in the file
itself, whereas the generatable content must be edited via templates in
this file.

# We did try to do the wrapping the smart way,
# with callable functions and new.function, but could never get the
# docstrings right for python2.2.  See
# For some later history, see

from __future__ import (absolute_import, division, print_function,

import six

import os
import inspect
import random
import types

import textwrap

# this line imports the installed copy of matplotlib, and not the local copy
from matplotlib.axes import Axes

# this is the magic line that must exist in pyplot, after which the boilerplate content will be
# appended
PYPLOT_MAGIC_HEADER = '################# REMAINING CONTENT GENERATED BY ##############\n'

PYPLOT_PATH = os.path.join(os.path.dirname(__file__), 'lib',
                               'matplotlib', '')

# This function was autogenerated by  Do not edit as
# changes will be lost"""

def %(func)s(%(argspec)s):
    %(ax)s = gca()
    # allow callers to override the hold state by passing hold=True|False
    %(washold)s = %(ax)s.ishold()
    if hold is not None:
        %(ret)s = %(ax)s.%(func)s(%(call)s)
    return %(ret)s

# Used for misc functions such as cla/legend etc.
def %(func)s(%(argspec)s):
    %(ret)s = gca().%(func)s(%(call)s)
    return %(ret)s

# Used for colormap functions
def {name}():
    set the default colormap to {name} and apply to current image if any.
    See help(colormaps) for more information
    rc('image', cmap='{name}')
    im = gci()

    if im is not None:


def boilerplate_gen():
    """Generator of lines for the automated part of pyplot."""

    # these methods are all simple wrappers of Axes methods by the same
    # name.
    _plotcommands = (

    _misccommands = (

    cmappable = {
        'contour' : 'if %(ret)s._A is not None: sci(%(ret)s)',
        'contourf': 'if %(ret)s._A is not None: sci(%(ret)s)',
        'hexbin' :  'sci(%(ret)s)',
        'scatter' : 'sci(%(ret)s)',
        'pcolor'  : 'sci(%(ret)s)',
        'pcolormesh': 'sci(%(ret)s)',
        'hist2d' : 'sci(%(ret)s[-1])',
        'imshow'  : 'sci(%(ret)s)',
        #'spy'    :  'sci(%(ret)s)',  ### may return image or Line2D
        'quiver' :  'sci(%(ret)s)',
        'specgram'  : 'sci(%(ret)s[-1])',
        'streamplot' :  'sci(%(ret)s.lines)',
        'tricontour' : 'if %(ret)s._A is not None: sci(%(ret)s)',
        'tricontourf': 'if %(ret)s._A is not None: sci(%(ret)s)',
        'tripcolor'  : 'sci(%(ret)s)',


    def format_value(value):
        Format function default values as needed for inspect.formatargspec.
        The interesting part is a hard-coded list of functions used
        as defaults in pyplot methods.
        if isinstance(value, types.FunctionType):
            if value.__name__ in ('detrend_none', 'window_hanning'):
                return '=mlab.' + value.__name__
            if value.__name__ == 'mean':
                return '=np.' + value.__name__
            raise ValueError(('default value %s unknown to boilerplate.' + \
                             'formatvalue') % value)
        return '='+repr(value)

    text_wrapper = textwrap.TextWrapper(break_long_words=False)

    for fmt, cmdlist in [(PLOT_TEMPLATE, _plotcommands),
                         (MISC_FN_TEMPLATE, _misccommands)]:
        for func in cmdlist:
            # For some commands, an additional line is needed to set the
            # color map
            if func in cmappable:
                mappable = '    ' + cmappable[func] % locals()
                mappable = ''

            # Get argspec of wrapped function
            args, varargs, varkw, defaults = inspect.getargspec(getattr(Axes, func))
            args.pop(0) # remove 'self' argument
            if defaults is None:
                defaults = ()
                def_edited = []
                for val in defaults:
                    if isinstance(val, unicode):
                        val = val.encode('ascii', 'ignore')
                defaults = tuple(def_edited)

            # How to call the wrapped function
            call = []
            for i, arg in enumerate(args):
                if len(defaults) < len(args) - i:
                    call.append('%s' % arg)
                    call.append('%s=%s' % (arg, arg))

            if varargs is not None:
            if varkw is not None:
            call = ', '.join(call)

            text_wrapper.width = 80 - 19 - len(func)
            join_with = '\n' + ' ' * (18 + len(func))
            call = join_with.join(text_wrapper.wrap(call))

            # Add a hold keyword argument if needed (fmt is PLOT_TEMPLATE) and
            # possible (if *args is used, we can't just add a hold
            # argument in front of it since it would gobble one of the
            # arguments the user means to pass via *args)
            if varargs:
                sethold = "    hold = %(varkw)s.pop('hold', None)" % locals()
            elif fmt is PLOT_TEMPLATE:
                defaults = defaults + (None,)
                sethold = ''

            # Now we can build the argspec for defining the wrapper
            argspec = inspect.formatargspec(args, varargs, varkw, defaults,
            argspec = argspec[1:-1] # remove parens

            text_wrapper.width = 80 - 5 - len(func)
            join_with = '\n' + ' ' * (5 + len(func))
            argspec = join_with.join(text_wrapper.wrap(argspec))

            # A gensym-like facility in case some function takes an
            # argument named washold, ax, or ret
            washold, ret, ax = 'washold', 'ret', 'ax'
            bad = set(args) | set((varargs, varkw))
            while washold in bad or ret in bad or ax in bad:
                washold = 'washold' + str(random.randrange(10**12))
                ret = 'ret' + str(random.randrange(10**12))
                ax = 'ax' + str(random.randrange(10**12))

            # Since we can't avoid using some function names,
            # bail out if they are used as argument names
            for reserved in ('gca', 'gci', 'draw_if_interactive'):
                if reserved in bad:
                    msg = 'Axes method %s has kwarg named %s' % (func, reserved)
                    raise ValueError(msg)

            yield fmt % locals()

    cmaps = (
        'gray' ,
        'jet' ,
    # add all the colormaps (autumn, hsv, ....)
    for name in cmaps:
        yield CMAP_TEMPLATE.format(name=name)

    yield ''
    yield '_setup_pyplot_info_docstrings()'

def build_pyplot():
    pyplot_path = os.path.join(os.path.dirname(__file__), 'lib',
                               'matplotlib', '')

    pyplot_orig = open(pyplot_path, 'r').readlines()

        pyplot_orig = pyplot_orig[:pyplot_orig.index(PYPLOT_MAGIC_HEADER)+1]
    except IndexError:
        raise ValueError('The file *must* have the exact line: %s' % PYPLOT_MAGIC_HEADER)

    pyplot = open(pyplot_path, 'w')


if __name__ == '__main__':
    # Write the matplotlib.pyplot file