HW1 Done
This commit is contained in:
380
HW1_Stones/env/lib/python3.7/site-packages/matplotlib/patheffects.py
vendored
Normal file
380
HW1_Stones/env/lib/python3.7/site-packages/matplotlib/patheffects.py
vendored
Normal file
@@ -0,0 +1,380 @@
|
||||
"""
|
||||
Defines classes for path effects. The path effects are supported in
|
||||
:class:`~matplotlib.text.Text`, :class:`~matplotlib.lines.Line2D`
|
||||
and :class:`~matplotlib.patches.Patch`.
|
||||
"""
|
||||
|
||||
from matplotlib.backend_bases import RendererBase
|
||||
from matplotlib import colors as mcolors
|
||||
from matplotlib import patches as mpatches
|
||||
from matplotlib import transforms as mtransforms
|
||||
|
||||
|
||||
class AbstractPathEffect(object):
|
||||
"""
|
||||
A base class for path effects.
|
||||
|
||||
Subclasses should override the ``draw_path`` method to add effect
|
||||
functionality.
|
||||
|
||||
"""
|
||||
def __init__(self, offset=(0., 0.)):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
offset : pair of floats
|
||||
The offset to apply to the path, measured in points.
|
||||
"""
|
||||
self._offset = offset
|
||||
self._offset_trans = mtransforms.Affine2D()
|
||||
|
||||
def _offset_transform(self, renderer, transform):
|
||||
"""Apply the offset to the given transform."""
|
||||
offset_x = renderer.points_to_pixels(self._offset[0])
|
||||
offset_y = renderer.points_to_pixels(self._offset[1])
|
||||
return transform + self._offset_trans.clear().translate(offset_x,
|
||||
offset_y)
|
||||
|
||||
def _update_gc(self, gc, new_gc_dict):
|
||||
"""
|
||||
Update the given GraphicsCollection with the given
|
||||
dictionary of properties. The keys in the dictionary are used to
|
||||
identify the appropriate set_ method on the gc.
|
||||
|
||||
"""
|
||||
new_gc_dict = new_gc_dict.copy()
|
||||
|
||||
dashes = new_gc_dict.pop("dashes", None)
|
||||
if dashes:
|
||||
gc.set_dashes(**dashes)
|
||||
|
||||
for k, v in new_gc_dict.items():
|
||||
set_method = getattr(gc, 'set_' + k, None)
|
||||
if not callable(set_method):
|
||||
raise AttributeError('Unknown property {0}'.format(k))
|
||||
set_method(v)
|
||||
return gc
|
||||
|
||||
def draw_path(self, renderer, gc, tpath, affine, rgbFace=None):
|
||||
"""
|
||||
Derived should override this method. The arguments are the same
|
||||
as :meth:`matplotlib.backend_bases.RendererBase.draw_path`
|
||||
except the first argument is a renderer.
|
||||
|
||||
"""
|
||||
# Get the real renderer, not a PathEffectRenderer.
|
||||
if isinstance(renderer, PathEffectRenderer):
|
||||
renderer = renderer._renderer
|
||||
return renderer.draw_path(gc, tpath, affine, rgbFace)
|
||||
|
||||
|
||||
class PathEffectRenderer(RendererBase):
|
||||
"""
|
||||
Implements a Renderer which contains another renderer.
|
||||
|
||||
This proxy then intercepts draw calls, calling the appropriate
|
||||
:class:`AbstractPathEffect` draw method.
|
||||
|
||||
.. note::
|
||||
Not all methods have been overridden on this RendererBase subclass.
|
||||
It may be necessary to add further methods to extend the PathEffects
|
||||
capabilities further.
|
||||
|
||||
"""
|
||||
def __init__(self, path_effects, renderer):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
path_effects : iterable of :class:`AbstractPathEffect`
|
||||
The path effects which this renderer represents.
|
||||
renderer : :class:`matplotlib.backend_bases.RendererBase` instance
|
||||
|
||||
"""
|
||||
self._path_effects = path_effects
|
||||
self._renderer = renderer
|
||||
|
||||
def new_gc(self):
|
||||
# docstring inherited
|
||||
return self._renderer.new_gc()
|
||||
|
||||
def copy_with_path_effect(self, path_effects):
|
||||
return self.__class__(path_effects, self._renderer)
|
||||
|
||||
def draw_path(self, gc, tpath, affine, rgbFace=None):
|
||||
for path_effect in self._path_effects:
|
||||
path_effect.draw_path(self._renderer, gc, tpath, affine,
|
||||
rgbFace)
|
||||
|
||||
def draw_markers(
|
||||
self, gc, marker_path, marker_trans, path, *args, **kwargs):
|
||||
# We do a little shimmy so that all markers are drawn for each path
|
||||
# effect in turn. Essentially, we induce recursion (depth 1) which is
|
||||
# terminated once we have just a single path effect to work with.
|
||||
if len(self._path_effects) == 1:
|
||||
# Call the base path effect function - this uses the unoptimised
|
||||
# approach of calling "draw_path" multiple times.
|
||||
return RendererBase.draw_markers(self, gc, marker_path,
|
||||
marker_trans, path, *args,
|
||||
**kwargs)
|
||||
|
||||
for path_effect in self._path_effects:
|
||||
renderer = self.copy_with_path_effect([path_effect])
|
||||
# Recursively call this method, only next time we will only have
|
||||
# one path effect.
|
||||
renderer.draw_markers(gc, marker_path, marker_trans, path,
|
||||
*args, **kwargs)
|
||||
|
||||
def draw_path_collection(self, gc, master_transform, paths, *args,
|
||||
**kwargs):
|
||||
# We do a little shimmy so that all paths are drawn for each path
|
||||
# effect in turn. Essentially, we induce recursion (depth 1) which is
|
||||
# terminated once we have just a single path effect to work with.
|
||||
if len(self._path_effects) == 1:
|
||||
# Call the base path effect function - this uses the unoptimised
|
||||
# approach of calling "draw_path" multiple times.
|
||||
return RendererBase.draw_path_collection(self, gc,
|
||||
master_transform, paths,
|
||||
*args, **kwargs)
|
||||
|
||||
for path_effect in self._path_effects:
|
||||
renderer = self.copy_with_path_effect([path_effect])
|
||||
# Recursively call this method, only next time we will only have
|
||||
# one path effect.
|
||||
renderer.draw_path_collection(gc, master_transform, paths,
|
||||
*args, **kwargs)
|
||||
|
||||
def points_to_pixels(self, points):
|
||||
# docstring inherited
|
||||
return self._renderer.points_to_pixels(points)
|
||||
|
||||
def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath):
|
||||
# Implements the naive text drawing as is found in RendererBase.
|
||||
path, transform = self._get_text_path_transform(x, y, s, prop,
|
||||
angle, ismath)
|
||||
color = gc.get_rgb()
|
||||
gc.set_linewidth(0.0)
|
||||
self.draw_path(gc, path, transform, rgbFace=color)
|
||||
|
||||
def __getattribute__(self, name):
|
||||
if name in ['_text2path', 'flipy', 'height', 'width']:
|
||||
return getattr(self._renderer, name)
|
||||
else:
|
||||
return object.__getattribute__(self, name)
|
||||
|
||||
|
||||
class Normal(AbstractPathEffect):
|
||||
"""
|
||||
The "identity" PathEffect.
|
||||
|
||||
The Normal PathEffect's sole purpose is to draw the original artist with
|
||||
no special path effect.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Stroke(AbstractPathEffect):
|
||||
"""A line based PathEffect which re-draws a stroke."""
|
||||
def __init__(self, offset=(0, 0), **kwargs):
|
||||
"""
|
||||
The path will be stroked with its gc updated with the given
|
||||
keyword arguments, i.e., the keyword arguments should be valid
|
||||
gc parameter values.
|
||||
"""
|
||||
super().__init__(offset)
|
||||
self._gc = kwargs
|
||||
|
||||
def draw_path(self, renderer, gc, tpath, affine, rgbFace):
|
||||
"""
|
||||
draw the path with updated gc.
|
||||
"""
|
||||
# Do not modify the input! Use copy instead.
|
||||
|
||||
gc0 = renderer.new_gc()
|
||||
gc0.copy_properties(gc)
|
||||
|
||||
gc0 = self._update_gc(gc0, self._gc)
|
||||
trans = self._offset_transform(renderer, affine)
|
||||
renderer.draw_path(gc0, tpath, trans, rgbFace)
|
||||
gc0.restore()
|
||||
|
||||
|
||||
class withStroke(Stroke):
|
||||
"""
|
||||
Adds a simple :class:`Stroke` and then draws the
|
||||
original Artist to avoid needing to call :class:`Normal`.
|
||||
|
||||
"""
|
||||
def draw_path(self, renderer, gc, tpath, affine, rgbFace):
|
||||
Stroke.draw_path(self, renderer, gc, tpath, affine, rgbFace)
|
||||
renderer.draw_path(gc, tpath, affine, rgbFace)
|
||||
|
||||
|
||||
class SimplePatchShadow(AbstractPathEffect):
|
||||
"""A simple shadow via a filled patch."""
|
||||
def __init__(self, offset=(2, -2),
|
||||
shadow_rgbFace=None, alpha=None,
|
||||
rho=0.3, **kwargs):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
offset : pair of floats
|
||||
The offset of the shadow in points.
|
||||
shadow_rgbFace : color
|
||||
The shadow color.
|
||||
alpha : float
|
||||
The alpha transparency of the created shadow patch.
|
||||
Default is 0.3.
|
||||
http://matplotlib.1069221.n5.nabble.com/path-effects-question-td27630.html
|
||||
rho : float
|
||||
A scale factor to apply to the rgbFace color if `shadow_rgbFace`
|
||||
is not specified. Default is 0.3.
|
||||
**kwargs
|
||||
Extra keywords are stored and passed through to
|
||||
:meth:`AbstractPathEffect._update_gc`.
|
||||
|
||||
"""
|
||||
super().__init__(offset)
|
||||
|
||||
if shadow_rgbFace is None:
|
||||
self._shadow_rgbFace = shadow_rgbFace
|
||||
else:
|
||||
self._shadow_rgbFace = mcolors.to_rgba(shadow_rgbFace)
|
||||
|
||||
if alpha is None:
|
||||
alpha = 0.3
|
||||
|
||||
self._alpha = alpha
|
||||
self._rho = rho
|
||||
|
||||
#: The dictionary of keywords to update the graphics collection with.
|
||||
self._gc = kwargs
|
||||
|
||||
def draw_path(self, renderer, gc, tpath, affine, rgbFace):
|
||||
"""
|
||||
Overrides the standard draw_path to add the shadow offset and
|
||||
necessary color changes for the shadow.
|
||||
|
||||
"""
|
||||
# IMPORTANT: Do not modify the input - we copy everything instead.
|
||||
affine0 = self._offset_transform(renderer, affine)
|
||||
gc0 = renderer.new_gc()
|
||||
gc0.copy_properties(gc)
|
||||
|
||||
if self._shadow_rgbFace is None:
|
||||
r, g, b = (rgbFace or (1., 1., 1.))[:3]
|
||||
# Scale the colors by a factor to improve the shadow effect.
|
||||
shadow_rgbFace = (r * self._rho, g * self._rho, b * self._rho)
|
||||
else:
|
||||
shadow_rgbFace = self._shadow_rgbFace
|
||||
|
||||
gc0.set_foreground("none")
|
||||
gc0.set_alpha(self._alpha)
|
||||
gc0.set_linewidth(0)
|
||||
|
||||
gc0 = self._update_gc(gc0, self._gc)
|
||||
renderer.draw_path(gc0, tpath, affine0, shadow_rgbFace)
|
||||
gc0.restore()
|
||||
|
||||
|
||||
class withSimplePatchShadow(SimplePatchShadow):
|
||||
"""
|
||||
Adds a simple :class:`SimplePatchShadow` and then draws the
|
||||
original Artist to avoid needing to call :class:`Normal`.
|
||||
|
||||
"""
|
||||
def draw_path(self, renderer, gc, tpath, affine, rgbFace):
|
||||
SimplePatchShadow.draw_path(self, renderer, gc, tpath, affine, rgbFace)
|
||||
renderer.draw_path(gc, tpath, affine, rgbFace)
|
||||
|
||||
|
||||
class SimpleLineShadow(AbstractPathEffect):
|
||||
"""A simple shadow via a line."""
|
||||
def __init__(self, offset=(2, -2),
|
||||
shadow_color='k', alpha=0.3, rho=0.3, **kwargs):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
offset : pair of floats
|
||||
The offset to apply to the path, in points.
|
||||
shadow_color : color
|
||||
The shadow color. Default is black.
|
||||
A value of ``None`` takes the original artist's color
|
||||
with a scale factor of `rho`.
|
||||
alpha : float
|
||||
The alpha transparency of the created shadow patch.
|
||||
Default is 0.3.
|
||||
rho : float
|
||||
A scale factor to apply to the rgbFace color if `shadow_rgbFace`
|
||||
is ``None``. Default is 0.3.
|
||||
**kwargs
|
||||
Extra keywords are stored and passed through to
|
||||
:meth:`AbstractPathEffect._update_gc`.
|
||||
"""
|
||||
super().__init__(offset)
|
||||
if shadow_color is None:
|
||||
self._shadow_color = shadow_color
|
||||
else:
|
||||
self._shadow_color = mcolors.to_rgba(shadow_color)
|
||||
self._alpha = alpha
|
||||
self._rho = rho
|
||||
#: The dictionary of keywords to update the graphics collection with.
|
||||
self._gc = kwargs
|
||||
|
||||
def draw_path(self, renderer, gc, tpath, affine, rgbFace):
|
||||
"""
|
||||
Overrides the standard draw_path to add the shadow offset and
|
||||
necessary color changes for the shadow.
|
||||
|
||||
"""
|
||||
# IMPORTANT: Do not modify the input - we copy everything instead.
|
||||
affine0 = self._offset_transform(renderer, affine)
|
||||
gc0 = renderer.new_gc()
|
||||
gc0.copy_properties(gc)
|
||||
|
||||
if self._shadow_color is None:
|
||||
r, g, b = (gc0.get_foreground() or (1., 1., 1.))[:3]
|
||||
# Scale the colors by a factor to improve the shadow effect.
|
||||
shadow_rgbFace = (r * self._rho, g * self._rho, b * self._rho)
|
||||
else:
|
||||
shadow_rgbFace = self._shadow_color
|
||||
|
||||
fill_color = None
|
||||
|
||||
gc0.set_foreground(shadow_rgbFace)
|
||||
gc0.set_alpha(self._alpha)
|
||||
|
||||
gc0 = self._update_gc(gc0, self._gc)
|
||||
renderer.draw_path(gc0, tpath, affine0, fill_color)
|
||||
gc0.restore()
|
||||
|
||||
|
||||
class PathPatchEffect(AbstractPathEffect):
|
||||
"""
|
||||
Draws a :class:`~matplotlib.patches.PathPatch` instance whose Path
|
||||
comes from the original PathEffect artist.
|
||||
|
||||
"""
|
||||
def __init__(self, offset=(0, 0), **kwargs):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
offset : pair of floats
|
||||
The offset to apply to the path, in points.
|
||||
**kwargs
|
||||
All keyword arguments are passed through to the
|
||||
:class:`~matplotlib.patches.PathPatch` constructor. The
|
||||
properties which cannot be overridden are "path", "clip_box"
|
||||
"transform" and "clip_path".
|
||||
"""
|
||||
super().__init__(offset=offset)
|
||||
self.patch = mpatches.PathPatch([], **kwargs)
|
||||
|
||||
def draw_path(self, renderer, gc, tpath, affine, rgbFace):
|
||||
affine = self._offset_transform(renderer, affine)
|
||||
self.patch._path = tpath
|
||||
self.patch.set_transform(affine)
|
||||
self.patch.set_clip_box(gc.get_clip_rectangle())
|
||||
clip_path = gc.get_clip_path()
|
||||
if clip_path:
|
||||
self.patch.set_clip_path(*clip_path)
|
||||
self.patch.draw(renderer)
|
||||
Reference in New Issue
Block a user