content: """
  A special directive for generating a matplotlib plot.
  
  .. warning::
  
     This is a hacked version of plot_directive.py from Matplotlib.
     It's very much subject to change!
  
  
  Usage
  -----
  
  Can be used like this::
  
      .. plot:: examples/example.py
  
      .. plot::
  
         import matplotlib.pyplot as plt
         plt.plot([1,2,3], [4,5,6])
  
      .. plot::
  
         A plotting example:
  
         >>> import matplotlib.pyplot as plt
         >>> plt.plot([1,2,3], [4,5,6])
  
  The content is interpreted as doctest formatted if it has a line starting
  with ``>>>``.
  
  The ``plot`` directive supports the options
  
      format : {'python', 'doctest'}
          Specify the format of the input
  
      include-source : bool
          Whether to display the source code. Default can be changed in conf.py
  
  and the ``image`` directive options ``alt``, ``height``, ``width``,
  ``scale``, ``align``, ``class``.
  
  Configuration options
  ---------------------
  
  The plot directive has the following configuration options:
  
      plot_include_source
          Default value for the include-source option
  
      plot_pre_code
          Code that should be executed before each plot.
  
      plot_basedir
          Base directory, to which plot:: file names are relative to.
          (If None or empty, file names are relative to the directoly where
          the file containing the directive is.)
  
      plot_formats
          File formats to generate. List of tuples or strings::
  
              [(suffix, dpi), suffix, ...]
  
          that determine the file format and the DPI. For entries whose
          DPI was omitted, sensible defaults are chosen.
  
      plot_html_show_formats
          Whether to show links to the files in HTML.
  
  TODO
  ----
  
  * Refactor Latex output; now it's plain images, but it would be nice
    to make them appear side-by-side, or in floats.
  
  """
  from __future__ import division, absolute_import, print_function
  
  import sys, os, glob, shutil, imp, warnings, re, textwrap, traceback
  import sphinx
  
  if sys.version_info[0] >= 3:
      from io import StringIO
  else:
      from io import StringIO
  
  import warnings
  warnings.warn("A plot_directive module is also available under "
                "matplotlib.sphinxext; expect this numpydoc.plot_directive "
                "module to be deprecated after relevant features have been "
                "integrated there.",
                FutureWarning, stacklevel=2)
  
  
  #------------------------------------------------------------------------------
  # Registration hook
  #------------------------------------------------------------------------------
  
  def setup(app):
      setup.app = app
      setup.config = app.config
      setup.confdir = app.confdir
  
      app.add_config_value('plot_pre_code', '', True)
      app.add_config_value('plot_include_source', False, True)
      app.add_config_value('plot_formats', ['png', 'hires.png', 'pdf'], True)
      app.add_config_value('plot_basedir', None, True)
      app.add_config_value('plot_html_show_formats', True, True)
  
      app.add_directive('plot', plot_directive, True, (0, 1, False),
                        **plot_directive_options)
  
  #------------------------------------------------------------------------------
  # plot:: directive
  #------------------------------------------------------------------------------
  from docutils.parsers.rst import directives
  from docutils import nodes
  
  def plot_directive(name, arguments, options, content, lineno,
                     content_offset, block_text, state, state_machine):
      return run(arguments, content, options, state_machine, state, lineno)
  plot_directive.__doc__ = __doc__
  
  def _option_boolean(arg):
      if not arg or not arg.strip():
          # no argument given, assume used as a flag
          return True
      elif arg.strip().lower() in ('no', '0', 'false'):
          return False
      elif arg.strip().lower() in ('yes', '1', 'true'):
          return True
      else:
          raise ValueError('"%s" unknown boolean' % arg)
  
  def _option_format(arg):
      return directives.choice(arg, ('python', 'lisp'))
  
  def _option_align(arg):
      return directives.choice(arg, ("top", "middle", "bottom", "left", "center",
                                     "right"))
  
  plot_directive_options = {'alt': directives.unchanged,
                            'height': directives.length_or_unitless,
                            'width': directives.length_or_percentage_or_unitless,
                            'scale': directives.nonnegative_int,
                            'align': _option_align,
                            'class': directives.class_option,
                            'include-source': _option_boolean,
                            'format': _option_format,
                            }
  
  #------------------------------------------------------------------------------
  # Generating output
  #------------------------------------------------------------------------------
  
  from docutils import nodes, utils
  
  try:
      # Sphinx depends on either Jinja or Jinja2
      import jinja2
      def format_template(template, **kw):
          return jinja2.Template(template).render(**kw)
  except ImportError:
      import jinja
      def format_template(template, **kw):
          return jinja.from_string(template, **kw)
  
  TEMPLATE = """
  {{ source_code }}
  
  {{ only_html }}
  
     {% if source_link or (html_show_formats and not multi_image) %}
     (
     {%- if source_link -%}
     `Source code <{{ source_link }}>`__
     {%- endif -%}
     {%- if html_show_formats and not multi_image -%}
       {%- for img in images -%}
         {%- for fmt in img.formats -%}
           {%- if source_link or not loop.first -%}, {% endif -%}
           `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__
         {%- endfor -%}
       {%- endfor -%}
     {%- endif -%}
     )
     {% endif %}
  
     {% for img in images %}
     .. figure:: {{ build_dir }}/{{ img.basename }}.png
        {%- for option in options %}
        {{ option }}
        {% endfor %}
  
        {% if html_show_formats and multi_image -%}
          (
          {%- for fmt in img.formats -%}
          {%- if not loop.first -%}, {% endif -%}
          `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__
          {%- endfor -%}
          )
        {%- endif -%}
     {% endfor %}
  
  {{ only_latex }}
  
     {% for img in images %}
     .. image:: {{ build_dir }}/{{ img.basename }}.pdf
     {% endfor %}
  
  """
  
  class ImageFile(object):
      def __init__(self, basename, dirname):
          self.basename = basename
          self.dirname = dirname
          self.formats = []
  
      def filename(self, format):
          return os.path.join(self.dirname, "%s.%s" % (self.basename, format))
  
      def filenames(self):
          return [self.filename(fmt) for fmt in self.formats]
  
  def run(arguments, content, options, state_machine, state, lineno):
      if arguments and content:
          raise RuntimeError("plot:: directive can't have both args and content")
  
      document = state_machine.document
      config = document.settings.env.config
  
      options.setdefault('include-source', config.plot_include_source)
  
      # determine input
      rst_file = document.attributes['source']
      rst_dir = os.path.dirname(rst_file)
  
      if arguments:
          if not config.plot_basedir:
              source_file_name = os.path.join(rst_dir,
                                              directives.uri(arguments[0]))
          else:
              source_file_name = os.path.join(setup.confdir, config.plot_basedir,
                                              directives.uri(arguments[0]))
          code = open(source_file_name, 'r').read()
          output_base = os.path.basename(source_file_name)
      else:
          source_file_name = rst_file
          code = textwrap.dedent("\n".join(map(str, content)))
          counter = document.attributes.get('_plot_counter', 0) + 1
          document.attributes['_plot_counter'] = counter
          base, ext = os.path.splitext(os.path.basename(source_file_name))
          output_base = '%s-%d.py' % (base, counter)
  
      base, source_ext = os.path.splitext(output_base)
      if source_ext in ('.py', '.rst', '.txt'):
          output_base = base
      else:
          source_ext = ''
  
      # ensure that LaTeX includegraphics doesn't choke in foo.bar.pdf filenames
      output_base = output_base.replace('.', '-')
  
      # is it in doctest format?
      is_doctest = contains_doctest(code)
      if 'format' in options:
          if options['format'] == 'python':
              is_doctest = False
          else:
              is_doctest = True
  
      # determine output directory name fragment
      source_rel_name = relpath(source_file_name, setup.confdir)
      source_rel_dir = os.path.dirname(source_rel_name)
      while source_rel_dir.startswith(os.path.sep):
          source_rel_dir = source_rel_dir[1:]
  
      # build_dir: where to place output files (temporarily)
      build_dir = os.path.join(os.path.dirname(setup.app.doctreedir),
                               'plot_directive',
                               source_rel_dir)
      if not os.path.exists(build_dir):
          os.makedirs(build_dir)
  
      # output_dir: final location in the builder's directory
      dest_dir = os.path.abspath(os.path.join(setup.app.builder.outdir,
                                              source_rel_dir))
  
      # how to link to files from the RST file
      dest_dir_link = os.path.join(relpath(setup.confdir, rst_dir),
                                   source_rel_dir).replace(os.path.sep, '/')
      build_dir_link = relpath(build_dir, rst_dir).replace(os.path.sep, '/')
      source_link = dest_dir_link + '/' + output_base + source_ext
  
      # make figures
      try:
          results = makefig(code, source_file_name, build_dir, output_base,
                            config)
          errors = []
      except PlotError as err:
          reporter = state.memo.reporter
          sm = reporter.system_message(
              2, "Exception occurred in plotting %s: %s" % (output_base, err),
              line=lineno)
          results = [(code, [])]
          errors = [sm]
  
      # generate output restructuredtext
      total_lines = []
      for j, (code_piece, images) in enumerate(results):
          if options['include-source']:
              if is_doctest:
                  lines = ['']
                  lines += [row.rstrip() for row in code_piece.split('\n')]
              else:
                  lines = ['.. code-block:: python', '']
                  lines += ['    %s' % row.rstrip()
                            for row in code_piece.split('\n')]
              source_code = "\n".join(lines)
          else:
              source_code = ""
  
          opts = [':%s: %s' % (key, val) for key, val in list(options.items())
                  if key in ('alt', 'height', 'width', 'scale', 'align', 'class')]
  
          only_html = ".. only:: html"
          only_latex = ".. only:: latex"
  
          if j == 0:
              src_link = source_link
          else:
              src_link = None
  
          result = format_template(
              TEMPLATE,
              dest_dir=dest_dir_link,
              build_dir=build_dir_link,
              source_link=src_link,
              multi_image=len(images) > 1,
              only_html=only_html,
              only_latex=only_latex,
              options=opts,
              images=images,
              source_code=source_code,
              html_show_formats=config.plot_html_show_formats)
  
          total_lines.extend(result.split("\n"))
          total_lines.extend("\n")
  
      if total_lines:
          state_machine.insert_input(total_lines, source=source_file_name)
  
      # copy image files to builder's output directory
      if not os.path.exists(dest_dir):
          os.makedirs(dest_dir)
  
      for code_piece, images in results:
          for img in images:
              for fn in img.filenames():
                  shutil.copyfile(fn, os.path.join(dest_dir,
                                                   os.path.basename(fn)))
  
      # copy script (if necessary)
      if source_file_name == rst_file:
          target_name = os.path.join(dest_dir, output_base + source_ext)
          f = open(target_name, 'w')
          f.write(unescape_doctest(code))
          f.close()
  
      return errors
  
  
  #------------------------------------------------------------------------------
  # Run code and capture figures
  #------------------------------------------------------------------------------
  
  import matplotlib
  matplotlib.use('Agg')
  import matplotlib.pyplot as plt
  import matplotlib.image as image
  from matplotlib import _pylab_helpers
  
  import exceptions
  
  def contains_doctest(text):
      try:
          # check if it's valid Python as-is
          compile(text, '<string>', 'exec')
          return False
      except SyntaxError:
          pass
      r = re.compile(r'^\s*>>>', re.M)
      m = r.search(text)
      return bool(m)
  
  def unescape_doctest(text):
      """
      Extract code from a piece of text, which contains either Python code
      or doctests.
  
      """
      if not contains_doctest(text):
          return text
  
      code = ""
      for line in text.split("\n"):
          m = re.match(r'^\s*(>>>|\.\.\.) (.*)$', line)
          if m:
              code += m.group(2) + "\n"
          elif line.strip():
              code += "# " + line.strip() + "\n"
          else:
              code += "\n"
      return code
  
  def split_code_at_show(text):
      """
      Split code at plt.show()
  
      """
  
      parts = []
      is_doctest = contains_doctest(text)
  
      part = []
      for line in text.split("\n"):
          if (not is_doctest and line.strip() == 'plt.show()') or \
                 (is_doctest and line.strip() == '>>> plt.show()'):
              part.append(line)
              parts.append("\n".join(part))
              part = []
          else:
              part.append(line)
      if "\n".join(part).strip():
          parts.append("\n".join(part))
      return parts
  
  class PlotError(RuntimeError):
      pass
  
  def run_code(code, code_path, ns=None):
      # Change the working directory to the directory of the example, so
      # it can get at its data files, if any.
      pwd = os.getcwd()
      old_sys_path = list(sys.path)
      if code_path is not None:
          dirname = os.path.abspath(os.path.dirname(code_path))
          os.chdir(dirname)
          sys.path.insert(0, dirname)
  
      # Redirect stdout
      stdout = sys.stdout
      sys.stdout = StringIO()
  
      # Reset sys.argv
      old_sys_argv = sys.argv
      sys.argv = [code_path]
      
      try:
          try:
              code = unescape_doctest(code)
              if ns is None:
                  ns = {}
              if not ns:
                  exec(setup.config.plot_pre_code, ns)
              exec(code, ns)
          except (Exception, SystemExit) as err:
              raise PlotError(traceback.format_exc())
      finally:
          os.chdir(pwd)
          sys.argv = old_sys_argv
          sys.path[:] = old_sys_path
          sys.stdout = stdout
      return ns
  
  
  #------------------------------------------------------------------------------
  # Generating figures
  #------------------------------------------------------------------------------
  
  def out_of_date(original, derived):
      """
      Returns True if derivative is out-of-date wrt original,
      both of which are full file paths.
      """
      return (not os.path.exists(derived)
              or os.stat(derived).st_mtime < os.stat(original).st_mtime)
  
  
  def makefig(code, code_path, output_dir, output_base, config):
      """
      Run a pyplot script *code* and save the images under *output_dir*
      with file names derived from *output_base*
  
      """
  
      # -- Parse format list
      default_dpi = {'png': 80, 'hires.png': 200, 'pdf': 50}
      formats = []
      for fmt in config.plot_formats:
          if isinstance(fmt, str):
              formats.append((fmt, default_dpi.get(fmt, 80)))
          elif type(fmt) in (tuple, list) and len(fmt)==2:
              formats.append((str(fmt[0]), int(fmt[1])))
          else:
              raise PlotError('invalid image format "%r" in plot_formats' % fmt)
  
      # -- Try to determine if all images already exist
  
      code_pieces = split_code_at_show(code)
  
      # Look for single-figure output files first
      all_exists = True
      img = ImageFile(output_base, output_dir)
      for format, dpi in formats:
          if out_of_date(code_path, img.filename(format)):
              all_exists = False
              break
          img.formats.append(format)
  
      if all_exists:
          return [(code, [img])]
  
      # Then look for multi-figure output files
      results = []
      all_exists = True
      for i, code_piece in enumerate(code_pieces):
          images = []
          for j in range(1000):
              img = ImageFile('%s_%02d_%02d' % (output_base, i, j), output_dir)
              for format, dpi in formats:
                  if out_of_date(code_path, img.filename(format)):
                      all_exists = False
                      break
                  img.formats.append(format)
  
              # assume that if we have one, we have them all
              if not all_exists:
                  all_exists = (j > 0)
                  break
              images.append(img)
          if not all_exists:
              break
          results.append((code_piece, images))
  
      if all_exists:
          return results
  
      # -- We didn't find the files, so build them
  
      results = []
      ns = {}
  
      for i, code_piece in enumerate(code_pieces):
          # Clear between runs
          plt.close('all')
  
          # Run code
          run_code(code_piece, code_path, ns)
  
          # Collect images
          images = []
          fig_managers = _pylab_helpers.Gcf.get_all_fig_managers()
          for j, figman in enumerate(fig_managers):
              if len(fig_managers) == 1 and len(code_pieces) == 1:
                  img = ImageFile(output_base, output_dir)
              else:
                  img = ImageFile("%s_%02d_%02d" % (output_base, i, j),
                                  output_dir)
              images.append(img)
              for format, dpi in formats:
                  try:
                      figman.canvas.figure.savefig(img.filename(format), dpi=dpi)
                  except exceptions.BaseException as err:
                      raise PlotError(traceback.format_exc())
                  img.formats.append(format)
  
          # Results
          results.append((code_piece, images))
  
      return results
  
  
  #------------------------------------------------------------------------------
  # Relative pathnames
  #------------------------------------------------------------------------------
  
  try:
      from os.path import relpath
  except ImportError:
      # Copied from Python 2.7
      if 'posix' in sys.builtin_module_names:
          def relpath(path, start=os.path.curdir):
              """Return a relative version of a path"""
              from os.path import sep, curdir, join, abspath, commonprefix, \
                   pardir
  
              if not path:
                  raise ValueError("no path specified")
  
              start_list = abspath(start).split(sep)
              path_list = abspath(path).split(sep)
  
              # Work out how much of the filepath is shared by start and path.
              i = len(commonprefix([start_list, path_list]))
  
              rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
              if not rel_list:
                  return curdir
              return join(*rel_list)
      elif 'nt' in sys.builtin_module_names:
          def relpath(path, start=os.path.curdir):
              """Return a relative version of a path"""
              from os.path import sep, curdir, join, abspath, commonprefix, \
                   pardir, splitunc
  
              if not path:
                  raise ValueError("no path specified")
              start_list = abspath(start).split(sep)
              path_list = abspath(path).split(sep)
              if start_list[0].lower() != path_list[0].lower():
                  unc_path, rest = splitunc(path)
                  unc_start, rest = splitunc(start)
                  if bool(unc_path) ^ bool(unc_start):
                      raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
                                                                          % (path, start))
                  else:
                      raise ValueError("path is on drive %s, start on drive %s"
                                                          % (path_list[0], start_list[0]))
              # Work out how much of the filepath is shared by start and path.
              for i in range(min(len(start_list), len(path_list))):
                  if start_list[i].lower() != path_list[i].lower():
                      break
              else:
                  i += 1
  
              rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
              if not rel_list:
                  return curdir
              return join(*rel_list)
      else:
          raise RuntimeError("Unsupported platform (no relpath available!)")
  