[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/feisuo/matplotlib/master/lib/matplotlib/path.py [Back]  [Original]

"""
A module for dealing with the polylines used throughout matplotlib.

The primary class for polyline handling in matplotlib is :class:`Path`.
Almost all vector drawing makes use of Paths somewhere in the drawing
pipeline.

Whilst a :class:`Path` instance itself cannot be drawn, there exists
:class:`~matplotlib.artist.Artist` subclasses which can be used for
convenient Path visualisation - the two most frequently used of these are
:class:`~matplotlib.patches.PathPatch` and
:class:`~matplotlib.collections.PathCollection`.
"""

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import six

import math
from weakref import WeakValueDictionary

import numpy as np

from matplotlib import _path
from matplotlib.cbook import simple_linear_interpolation, maxdict
from matplotlib import rcParams


class Path(object):
    """
    :class:`Path` represents a series of possibly disconnected,
    possibly closed, line and curve segments.

    The underlying storage is made up of two parallel numpy arrays:
      - *vertices*: an Nx2 float array of vertices
      - *codes*: an N-length uint8 array of vertex types

    These two arrays always have the same length in the first
    dimension.  For example, to represent a cubic curve, you must
    provide three vertices as well as three codes ``CURVE3``.

    The code types are:

       - ``STOP``   :  1 vertex (ignored)
           A marker for the end of the entire path (currently not
           required and ignored)

       - ``MOVETO`` :  1 vertex
            Pick up the pen and move to the given vertex.

       - ``LINETO`` :  1 vertex
            Draw a line from the current position to the given vertex.

       - ``CURVE3`` :  1 control point, 1 endpoint
          Draw a quadratic Bezier curve from the current position,
          with the given control point, to the given end point.

       - ``CURVE4`` :  2 control points, 1 endpoint
          Draw a cubic Bezier curve from the current position, with
          the given control points, to the given end point.

       - ``CLOSEPOLY`` : 1 vertex (ignored)
          Draw a line segment to the start point of the current
          polyline.

    Users of Path objects should not access the vertices and codes
    arrays directly.  Instead, they should use :meth:`iter_segments`
    or :meth:`cleaned` to get the vertex/code pairs.  This is important,
    since many :class:`Path` objects, as an optimization, do not store a
    *codes* at all, but have a default one provided for them by
    :meth:`iter_segments`.

    .. note::

        The vertices and codes arrays should be treated as
        immutable -- there are a number of optimizations and assumptions
        made up front in the constructor that will not change when the
        data changes.

    """

    # Path codes
    STOP = 0         # 1 vertex
    MOVETO = 1       # 1 vertex
    LINETO = 2       # 1 vertex
    CURVE3 = 3       # 2 vertices
    CURVE4 = 4       # 3 vertices
    CLOSEPOLY = 79   # 1 vertex

    #: A dictionary mapping Path codes to the number of vertices that the
    #: code expects.
    NUM_VERTICES_FOR_CODE = {STOP: 1,
                             MOVETO: 1,
                             LINETO: 1,
                             CURVE3: 2,
                             CURVE4: 3,
                             CLOSEPOLY: 1}

    code_type = np.uint8

    def __init__(self, vertices, codes=None, _interpolation_steps=1,
                 closed=False, readonly=False):
        """
        Create a new path with the given vertices and codes.

        Parameters
        ----------
        vertices : array_like
            The ``(n, 2)`` float array, masked array or sequence of pairs
            representing the vertices of the path.

            If *vertices* contains masked values, they will be converted
            to NaNs which are then handled correctly by the Agg
            PathIterator and other consumers of path data, such as
            :meth:`iter_segments`.
        codes : {None, array_like}, optional
            n-length array integers representing the codes of the path.
            If not None, codes must be the same length as vertices.
            If None, *vertices* will be treated as a series of line segments.
        _interpolation_steps : int, optional
            Used as a hint to certain projections, such as Polar, that this
            path should be linearly interpolated immediately before drawing.
            This attribute is primarily an implementation detail and is not
            intended for public use.
        closed : bool, optional
            If *codes* is None and closed is True, vertices will be treated as
            line segments of a closed polygon.
        readonly : bool, optional
            Makes the path behave in an immutable way and sets the vertices
            and codes as read-only arrays.
        """
        if isinstance(vertices, np.ma.MaskedArray):
            vertices = vertices.astype(float).filled(np.nan)
        else:
            vertices = np.asarray(vertices, float)

        if (vertices.ndim != 2) or (vertices.shape[1] != 2):
            msg = "'vertices' must be a 2D list or array with shape Nx2"
            raise ValueError(msg)

        if codes is not None:
            codes = np.asarray(codes, self.code_type)
            if (codes.ndim != 1) or len(codes) != len(vertices):
                msg = ("'codes' must be a 1D list or array with the same"
                       " length of 'vertices'")
                raise ValueError(msg)
            if len(codes) and codes[0] != self.MOVETO:
                msg = ("The first element of 'code' must be equal to 'MOVETO':"
                       " {0}")
                raise ValueError(msg.format(self.MOVETO))
        elif closed:
            codes = np.empty(len(vertices), dtype=self.code_type)
            codes[0] = self.MOVETO
            codes[1:-1] = self.LINETO
            codes[-1] = self.CLOSEPOLY

        self._vertices = vertices
        self._codes = codes
        self._interpolation_steps = _interpolation_steps
        self._update_values()

        if readonly:
            self._vertices.flags.writeable = False
            if self._codes is not None:
                self._codes.flags.writeable = False
            self._readonly = True
        else:
            self._readonly = False

    @classmethod
    def _fast_from_codes_and_verts(cls, verts, codes, internals=None):
        """
        Creates a Path instance without the expense of calling the constructor

        Parameters
        ----------
        verts : numpy array
        codes : numpy array
        internals : dict or None
            The attributes that the resulting path should have.
            Allowed keys are ``readonly``, ``should_simplify``,
            ``simplify_threshold``, ``has_nonfinite`` and
            ``interpolation_steps``.

        """
        internals = internals or {}
        pth = cls.__new__(cls)
        if isinstance(verts, np.ma.MaskedArray):
            verts = verts.astype(float).filled(np.nan)
        else:
            verts = np.asarray(verts, float)
        pth._vertices = verts
        pth._codes = codes
        pth._readonly = internals.pop('readonly', False)
        pth.should_simplify = internals.pop('should_simplify', True)
        pth.simplify_threshold = (
            internals.pop('simplify_threshold',
                          rcParams['path.simplify_threshold'])
        )
        pth._has_nonfinite = internals.pop('has_nonfinite', False)
        pth._interpolation_steps = internals.pop('interpolation_steps', 1)
        if internals:
            raise ValueError('Unexpected internals provided to '
                             '_fast_from_codes_and_verts: '
                             '{0}'.format('\n *'.join(six.iterkeys(
                                 internals
                             ))))
        return pth

    def _update_values(self):
        self._should_simplify = (
            rcParams['path.simplify'] and
            (len(self._vertices) >= 128 and
             (self._codes is None or np.all(self._codes 

Web Proxy Viewer  |  New URL  |  Original Page