Skip to content

Commit 157eec9

Browse files
committed
Merge pull request #1227 from mdboom/cairocffi
Does the gtk3agg backend work on python3?
2 parents fcdb600 + 8c85074 commit 157eec9

File tree

5 files changed

+68
-16
lines changed

5 files changed

+68
-16
lines changed

doc/users/whats_new.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,19 @@ added. Furthermore, the the subplottool is now implemented as a modal
149149
dialog. It was previously a QMainWindow, leaving the SPT open if one closed the
150150
plotwindow.
151151

152+
Cairo backends
153+
``````````````
154+
155+
The Cairo backends are now able to use the `cairocffi bindings
156+
<https://github.com/SimonSapin/cairocffi>`__ which are more actively
157+
maintained than the `pycairo bindings
158+
<http://cairographics.org/pycairo/>`__.
159+
160+
Gtk3Agg backend
161+
```````````````
162+
163+
The Gtk3Agg backend now works on Python 3.x, if the `cairocffi
164+
bindings <https://github.com/SimonSapin/cairocffi>`__ are installed.
152165

153166
Text
154167
----

lib/matplotlib/backends/backend_cairo.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,16 @@
3030
def _fn_name(): return sys._getframe(1).f_code.co_name
3131

3232
try:
33-
import cairo
33+
import cairocffi as cairo
3434
except ImportError:
35-
raise ImportError("Cairo backend requires that pycairo is installed.")
35+
try:
36+
import cairo
37+
except ImportError:
38+
raise ImportError("Cairo backend requires that cairocffi or pycairo is installed.")
39+
else:
40+
HAS_CAIRO_CFFI = False
41+
else:
42+
HAS_CAIRO_CFFI = True
3643

3744
_version_required = (1,2,0)
3845
if cairo.version_info < _version_required:
@@ -197,8 +204,14 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
197204
if angle:
198205
ctx.rotate (-angle * np.pi / 180)
199206
ctx.set_font_size (size)
200-
if isinstance(s, six.text_type):
201-
s = s.encode("utf-8")
207+
208+
if HAS_CAIRO_CFFI:
209+
if not isinstance(s, six.text_type):
210+
s = six.text_type(s)
211+
else:
212+
if isinstance(s, six.text_type):
213+
s = s.encode("utf-8")
214+
202215
ctx.show_text(s)
203216
ctx.restore()
204217

@@ -363,8 +376,8 @@ def set_dashes(self, offset, dashes):
363376
if dashes == None:
364377
self.ctx.set_dash([], 0) # switch dashes off
365378
else:
366-
self.ctx.set_dash (
367-
self.renderer.points_to_pixels (np.asarray(dashes)), offset)
379+
self.ctx.set_dash(
380+
list(self.renderer.points_to_pixels(np.asarray(dashes))), offset)
368381

369382

370383
def set_foreground(self, fg, isRGBA=None):

lib/matplotlib/backends/backend_gtk3agg.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33

44
import six
55

6-
import cairo
76
import numpy as np
87
import sys
98
import warnings
109

1110
from . import backend_agg
1211
from . import backend_gtk3
12+
from .backend_cairo import cairo, HAS_CAIRO_CFFI
1313
from matplotlib.figure import Figure
1414
from matplotlib import transforms
1515

16-
if six.PY3:
17-
warnings.warn("The Gtk3Agg backend is not known to work on Python 3.x.")
16+
if six.PY3 and not HAS_CAIRO_CFFI:
17+
warnings.warn(
18+
"The Gtk3Agg backend is known to not work on Python 3.x with pycairo. "
19+
"Try installing cairocffi.")
1820

1921

2022
class FigureCanvasGTK3Agg(backend_gtk3.FigureCanvasGTK3,
@@ -53,8 +55,16 @@ def on_draw_event(self, widget, ctx):
5355
width = int(bbox.x1) - int(bbox.x0)
5456
height = int(bbox.y1) - int(bbox.y0)
5557

56-
image = cairo.ImageSurface.create_for_data(
57-
buf, cairo.FORMAT_ARGB32, width, height)
58+
if HAS_CAIRO_CFFI:
59+
ctx = cairo.Context._from_pointer(
60+
cairo.ffi.cast('cairo_t **',
61+
id(ctx) + object.__basicsize__)[0],
62+
incref=True)
63+
image = cairo.ImageSurface.create_for_data(
64+
buf.data, cairo.FORMAT_ARGB32, width, height)
65+
else:
66+
image = cairo.ImageSurface.create_for_data(
67+
buf, cairo.FORMAT_ARGB32, width, height)
5868
ctx.set_source_surface(image, x, y)
5969
ctx.paint()
6070

lib/matplotlib/backends/backend_gtk3cairo.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@
55

66
from . import backend_gtk3
77
from . import backend_cairo
8+
from .backend_cairo import cairo, HAS_CAIRO_CFFI
89
from matplotlib.figure import Figure
910

1011
class RendererGTK3Cairo(backend_cairo.RendererCairo):
1112
def set_context(self, ctx):
13+
if HAS_CAIRO_CFFI:
14+
ctx = cairo.Context._from_pointer(
15+
cairo.ffi.cast(
16+
'cairo_t **',
17+
id(ctx) + object.__basicsize__)[0],
18+
incref=True)
19+
1220
self.gc.ctx = ctx
1321

1422

setupext.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,9 +1699,12 @@ def get_package_data(self):
16991699

17001700
def backend_gtk3cairo_internal_check(x):
17011701
try:
1702-
import cairo
1702+
import cairocffi
17031703
except ImportError:
1704-
return (False, "Requires cairo to be installed.")
1704+
try:
1705+
import cairo
1706+
except ImportError:
1707+
return (False, "Requires cairocffi or pycairo to be installed.")
17051708

17061709
try:
17071710
import gi
@@ -1891,11 +1894,16 @@ class BackendCairo(OptionalBackendPackage):
18911894

18921895
def check_requirements(self):
18931896
try:
1894-
import cairo
1897+
import cairocffi
18951898
except ImportError:
1896-
raise CheckFailed("cairo not found")
1899+
try:
1900+
import cairo
1901+
except ImportError:
1902+
raise CheckFailed("cairocffi or pycairo not found")
1903+
else:
1904+
return "pycairo version %s" % cairo.version
18971905
else:
1898-
return "version %s" % cairo.version
1906+
return "cairocffi version %s" % cairocffi.version
18991907

19001908

19011909
class DviPng(SetupPackage):

0 commit comments

Comments
 (0)