8000 Use Agg for rendering in the Mac OSX backend by mdboom · Pull Request #6178 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Use Agg for rendering in the Mac OSX backend #6178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 28, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Use Agg for rendering in the Mac OSX backend
  • Loading branch information
mdboom committed Mar 17, 2016
commit eea4d80edbb39cc76fbfaece74a770c3b4e2f682
242 changes: 34 additions & 208 deletions lib/matplotlib/backends/backend_macosx.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,231 +4,29 @@
from matplotlib.externals import six

import os
import numpy

from matplotlib._pylab_helpers import Gcf
from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\
FigureManagerBase, FigureCanvasBase, NavigationToolbar2, TimerBase
from matplotlib.backend_bases import FigureManagerBase, FigureCanvasBase, \
NavigationToolbar2, TimerBase
from matplotlib.backend_bases import ShowBase

from matplotlib.cbook import maxdict
from matplotlib.figure import Figure
from matplotlib.path import Path
from matplotlib.mathtext import MathTextParser
from matplotlib.colors import colorConverter
from matplotlib import rcParams

from matplotlib.widgets import SubplotTool

import matplotlib
from matplotlib.backends import _macosx

from .backend_agg import RendererAgg


class Show(ShowBase):
def mainloop(self):
_macosx.show()
show = Show()


class RendererMac(RendererBase):
"""
The renderer handles drawing/rendering operations. Most of the renderer's
methods forward the command to the renderer's graphics context. The
renderer does not wrap a C object and is written in pure Python.
"""

texd = maxdict(50) # a cache of tex image rasters

def __init__(self, dpi, width, height):
RendererBase.__init__(self)
self.dpi = dpi
self.width = width
self.height = height
self.gc = GraphicsContextMac()
self.gc.set_dpi(self.dpi)
self.mathtext_parser = MathTextParser('MacOSX')

def set_width_height (self, width, height):
self.width, self.height = width, height

def draw_path(self, gc, path, transform, rgbFace=None):
if rgbFace is not None:
rgbFace = tuple(rgbFace)
linewidth = gc.get_linewidth()
gc.draw_path(path, transform, linewidth, rgbFace)

def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
if rgbFace is not None:
rgbFace = tuple(rgbFace)
linewidth = gc.get_linewidth()
gc.draw_markers(marker_path, marker_trans, path, trans, linewidth, rgbFace)

def draw_path_collection(self, gc, master_transform, paths, all_transforms,
offsets, offsetTrans, facecolors, edgecolors,
linewidths, linestyles, antialiaseds, urls,
offset_position):
if offset_position=='data':
offset_position = True
else:
offset_position = False
path_ids = []
for path, transform in self._iter_collection_raw_paths(
master_transform, paths, all_transforms):
path_ids.append((path, transform))
master_transform = master_transform.get_matrix()
offsetTrans = offsetTrans.get_matrix()
gc.draw_path_collection(master_transform, path_ids, all_transforms,
offsets, offsetTrans, facecolors, edgecolors,
linewidths, linestyles, antialiaseds,
offset_position)

def draw_quad_mesh(self, gc, master_transform, meshWidth, meshHeight,
coordinates, offsets, offsetTrans, facecolors,
antialiased, edgecolors):
gc.draw_quad_mesh(master_transform.get_matrix(),
meshWidth,
meshHeight,
coordinates,
offsets,
offsetTrans.get_matrix(),
facecolors,
antialiased,
edgecolors)

def new_gc(self):
self.gc.save()
self.gc.set_hatch(None)
self.gc._alpha = 1.0
self.gc._forced_alpha = False # if True, _alpha overrides A from RGBA
return self.gc

def draw_gouraud_triangle(self, gc, points, colors, transform):
points = transform.transform(points)
gc.draw_gouraud_triangle(points, colors)

def get_image_magnification(self):
return self.gc.get_image_magnification()

def draw_image(self, gc, x, y, im):
nrows, ncols, data = im.as_rgba_str()
gc.draw_image(x, y, nrows, ncols, data)

def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None):
# todo, handle props, angle, origins
scale = self.gc.get_image_magnification()
size = prop.get_size_in_points()
texmanager = self.get_texmanager()
key = s, size, self.dpi, angle, texmanager.get_font_config()
im = self.texd.get(key) # Not sure what this does; just copied from backend_agg.py
if im is None:
Z = texmanager.get_grey(s, size, self.dpi*scale)
Z = numpy.array(255.0 - Z * 255.0, numpy.uint8)

gc.draw_mathtext(x, y, angle, Z)

def _draw_mathtext(self, gc, x, y, s, prop, angle):
scale = self.gc.get_image_magnification()
ox, oy, width, height, descent, image, used_characters = \
self.mathtext_parser.parse(s, self.dpi*scale, prop)
descent /= scale
xd = descent * numpy.sin(numpy.deg2rad(angle))
yd = descent * numpy.cos(numpy.deg2rad(angle))
x = numpy.round(x + ox + xd)
y = numpy.round(y + oy - yd)
gc.draw_mathtext(x, y, angle, 255 - image.as_array())

def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
if ismath:
self._draw_mathtext(gc, x, y, s, prop, angle)
else:
family = prop.get_family()
weight = prop.get_weight()
# transform weight into string for the native backend
if weight >= 700:
weight = 'bold'
else:
weight = 'normal'
style = prop.get_style()
points = prop.get_size_in_points()
size = self.points_to_pixels(points)
gc.draw_text(x, y, six.text_type(s), family, size, weight, style, angle)

def get_text_width_height_descent(self, s, prop, ismath):
if ismath=='TeX':
# todo: handle props
texmanager = self.get_texmanager()
fontsize = prop.get_size_in_points()
w, h, d = texmanager.get_text_width_height_descent(s, fontsize,
renderer=self)
return w, h, d
if ismath:
ox, oy, width, height, descent, fonts, used_characters = \
self.mathtext_parser.parse(s, self.dpi, prop)
return width, height, descent
family = prop.get_family()
weight = prop.get_weight()
# transform weight into string for the native backend
if weight >= 700:
weight = 'bold'
else:
weight = 'normal'
style = prop.get_style()
points = prop.get_size_in_points()
size = self.points_to_pixels(points)
width, height, descent = self.gc.get_text_width_height_descent(
six.text_type(s), family, size, weight, style)
return width, height, descent

def flipy(self):
return False

def points_to_pixels(self, points):
return points/72.0 * self.dpi

def option_image_nocomposite(self):
return True


class GraphicsContextMac(_macosx.GraphicsContext, GraphicsContextBase):
"""
The GraphicsContext wraps a Quartz graphics context. All methods
are implemented at the C-level in macosx.GraphicsContext. These
methods set drawing properties such as the line style, fill color,
etc. The actual drawing is done by the Renderer, which draws into
the GraphicsContext.
"""
def __init__(self):
GraphicsContextBase.__init__(self)
_macosx.GraphicsContext.__init__(self)

def set_alpha(self, alpha):
GraphicsContextBase.set_alpha(self, alpha)
_alpha = self.get_alpha()
_macosx.GraphicsContext.set_alpha(self, _alpha, self.get_forced_alpha())
rgb = self.get_rgb()
_macosx.GraphicsContext.set_foreground(self, rgb)

def set_foreground(self, fg, isRGBA=False):
GraphicsContextBase.set_foreground(self, fg, isRGBA)
rgb = self.get_rgb()
_macosx.GraphicsContext.set_foreground(self, rgb)

def set_graylevel(self, fg):
GraphicsContextBase.set_graylevel(self, fg)
_macosx.GraphicsContext.set_graylevel(self, fg)

def set_clip_rectangle(self, box):
GraphicsContextBase.set_clip_rectangle(self, box)
if not box: return
_macosx.GraphicsContext.set_clip_rectangle(self, box.bounds)

def set_clip_path(self, path):
GraphicsContextBase.set_clip_path(self, path)
if not path: return
path = path.get_fully_transformed_path()
_macosx.GraphicsContext.set_clip_path(self, path)


########################################################################
#
# The following functions and classes are for pylab and implement
Expand Down Expand Up @@ -311,14 +109,42 @@ class FigureCanvasMac(_macosx.FigureCanvas, FigureCanvasBase):
def __init__(self, figure):
FigureCanvasBase.__init__(self, figure)
width, height = self.get_width_height()
self.renderer = RendererMac(figure.dpi, width, height)
_macosx.FigureCanvas.__init__(self, width, height)

@property
def renderer(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tight_layout looks for get_renderer https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/tight_layout.py#L218 I guess we should either change it or implement get_renderer on top of the property

l, b, w, h = self.figure.bbox.bounds
key = w, h, self.figure.dpi
try:
self._lastKey, self._renderer
except AttributeError:
need_new_renderer = True
else:
need_new_renderer = (self._lastKey != key)

if need_new_renderer:
self._renderer = RendererAgg(w, h, self.figure.dpi)
self._lastKey = key

return self._renderer

def _draw(self, device_scale):
figure = self.figure

orig_dpi = figure.dpi
try:
figure.dpi *= device_scale
renderer = self.renderer
figure.draw(renderer)
finally:
figure.dpi = orig_dpi

return renderer

def draw_idle(self, *args, **kwargs):
self.invalidate()

def resize(self, width, height):
self.renderer.set_width_height(width, height)
dpi = self.figure.dpi
width /= dpi
height /= dpi
Expand Down
5 changes: 1 addition & 4 deletions setupext.py
Original file line number Diff line number Diff line change
Expand Up @@ -2140,14 +2140,11 @@ def check_requirements(self):

def get_extension(self):
sources = [
'src/_macosx.m',
'src/py_converters.cpp',
'src/path_cleanup.cpp'
'src/_macosx.m'
]

ext = make_extension('matplotlib.backends._macosx', sources)
Numpy().add_flags(ext)
LibAgg().add_flags(ext)
ext.extra_link_args.extend(['-framework', 'Cocoa'])
return ext

Expand Down
Loading
0