8000 Merge pull request #10514 from anntzer/gtk-and-cairo-compat-matrix · matplotlib/matplotlib@66499e1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 66499e1

Browse files
authored
Merge pull request #10514 from anntzer/gtk-and-cairo-compat-matrix
Cleanup/update cairo + gtk compatibility matrix.
2 parents 5619354 + a54c2c7 commit 66499e1

File tree

5 files changed

+58
-50
lines changed

5 files changed

+58
-50
lines changed

doc/sphinxext/mock_gui_toolkits.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
class MyCairoCffi(MagicMock):
6-
version_info = (1, 4, 0)
6+
pass
77

88

99
class MyPyQt4(MagicMock):

lib/matplotlib/backends/backend_cairo.py

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,17 @@
2525
"is installed")
2626
else:
2727
HAS_CAIRO_CFFI = False
28+
if cairo.version_info < (1, 11, 0):
29+
# Introduced create_for_data for Py3.
30+
raise ImportError(
31+
"cairo {} is installed; cairo>=1.11.0 is required"
32+
.format(cairo.version))
2833
else:
2934
HAS_CAIRO_CFFI = True
3035

31-
if cairo.version_info < (1, 4, 0):
32-
raise ImportError("cairo {} is installed; "
33-
"cairo>=1.4.0 is required".format(cairo.version))
3436
backend_version = cairo.version
3537

36-
from matplotlib import cbook
38+
from .. import cbook
3739
from matplotlib.backend_bases import (
3840
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
3941
RendererBase)
@@ -63,6 +65,23 @@ def _premultiplied_argb32_to_unmultiplied_rgba8888(buf):
6365
return rgba
6466

6567

68+
if HAS_CAIRO_CFFI:
69+
# Convert a pycairo context to a cairocffi one.
70+
def _to_context(ctx):
71+
if not isinstance(ctx, cairo.Context):
72+
ctx = cairo.Context._from_pointer(
73+
cairo.ffi.cast(
74+
'cairo_t **',
75+
id(ctx) + object.__basicsize__)[0],
76+
incref=True)
77+
return ctx
78+
else:
79+
# Pass-through a pycairo context.
80+
def _to_context(ctx):
81+
return ctx
82+
83+
84+
@cbook.deprecated("3.0")
6685
class ArrayWrapper:
6786
"""Thin wrapper around numpy ndarray to expose the interface
6887
expected by cairocffi. Basically replicates the
@@ -346,21 +365,9 @@ def draw_image(self, gc, x, y, im):
346365
im = im[:, :, (2, 1, 0, 3)]
347366
else:
348367
im = im[:, :, (3, 0, 1, 2)]
349-
if HAS_CAIRO_CFFI:
350-
# cairocffi tries to use the buffer_info from array.array
351-
# that we replicate in ArrayWrapper and alternatively falls back
352-
# on ctypes to get a pointer to the numpy array. This works
353-
# correctly on a numpy array in python3 but not 2.7. We replicate
354-
# the array.array functionality here to get cross version support.
355-
imbuffer = ArrayWrapper(im.ravel())
356-
else:
357-
# py2cairo uses PyObject_AsWriteBuffer to get a pointer to the
358-
# numpy array; this works correctly on a regular numpy array but
359-
# not on a memory view.
360-
imbuffer = im.ravel()
361368
surface = cairo.ImageSurface.create_for_data(
362-
imbuffer, cairo.FORMAT_ARGB32,
363-
im.shape[1], im.shape[0], im.shape[1]*4)
369+
im.ravel().data, cairo.FORMAT_ARGB32,
370+
im.shape[1], im.shape[0], im.shape[1] * 4)
364371
ctx = gc.ctx
365372
y = self.height - y - im.shape[0]
366373

lib/matplotlib/backends/backend_gtk3agg.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
import numpy as np
22
import warnings
33

4-
from . import backend_agg, backend_gtk3
5-
from .backend_cairo import cairo, HAS_CAIRO_CFFI
4+
from . import backend_agg, backend_cairo, backend_gtk3
5+
from ._gtk3_compat import gi
6+
from .backend_cairo import cairo
67
from .backend_gtk3 import _BackendGTK3
78
from matplotlib import transforms
89

9-
if not HAS_CAIRO_CFFI:
10-
warnings.warn(
11-
"The Gtk3Agg backend is known to not work on Python 3.x with pycairo. "
12-
"Try installing cairocffi.")
10+
# The following combinations are allowed:
11+
# gi + pycairo
12+
# gi + cairocffi
13+
# pgi + cairocffi
14+
# (pgi doesn't work with pycairo)
15+
# We always try to import cairocffi first so if a check below fails it means
16+
# that cairocffi was unavailable to start with.
17+
if gi.__name__ == "pgi" and cairo.__name__ == "cairo":
18+
raise ImportError("pgi and pycairo are not compatible")
1319

1420

1521
class FigureCanvasGTK3Agg(backend_gtk3.FigureCanvasGTK3,
@@ -36,11 +42,7 @@ def on_draw_event(self, widget, ctx):
3642
else:
3743
bbox_queue = self._bbox_queue
3844

39-
if HAS_CAIRO_CFFI and not isinstance(ctx, cairo.Context):
40-
ctx = cairo.Context._from_pointer(
41-
cairo.ffi.cast('cairo_t **',
42-
id(ctx) + object.__basicsize__)[0],
43-
incref=True)
45+
ctx = backend_cairo._to_context(ctx)
4446

4547
for bbox in bbox_queue:
4648
area = self.copy_from_bbox(bbox)
@@ -51,12 +53,9 @@ def on_draw_event(self, widget, ctx):
5153
width = int(bbox.x1) - int(bbox.x0)
5254
height = int(bbox.y1) - int(bbox.y0)
5355

54-
if HAS_CAIRO_CFFI:
55-
image = cairo.ImageSurface.create_for_data(
56-
buf.data, cairo.FORMAT_ARGB32, width, height)
57-
else:
58-
image = cairo.ImageSurface.create_for_data(
59-
buf, cairo.FORMAT_ARGB32, width, height)
56+
image = cairo.ImageSurface.create_for_data(
57+
buf.ravel().data, cairo.FORMAT_ARGB32,
58+
width, height, width * 4)
6059
ctx.set_source_surface(image, x, y)
6160
ctx.paint()
6261

lib/matplotlib/backends/backend_gtk3cairo.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
from . import backend_cairo, backend_gtk3
2-
from .backend_cairo import cairo, HAS_CAIRO_CFFI
2+
from ._gtk3_compat import gi
3+
from .backend_cairo import cairo
34
from .backend_gtk3 import _BackendGTK3
45
from matplotlib.backend_bases import cursors
56

67

8+
# The following combinations are allowed:
9+
# gi + pycairo
10+
# gi + cairocffi
11+
# pgi + cairocffi
12+
# (pgi doesn't work with pycairo)
13+
# We always try to import cairocffi first so if a check below fails it means
14+
# that cairocffi was unavailable to start with.
15+
if gi.__name__ == "pgi" and cairo.__name__ == "cairo":
16+
raise ImportError("pgi and pycairo are not compatible")
17+
18+
719
class RendererGTK3Cairo(backend_cairo.RendererCairo):
820
def set_context(self, ctx):
9-
if HAS_CAIRO_CFFI and not isinstance(ctx, cairo.Context):
10-
ctx = cairo.Context._from_pointer(
11-
cairo.ffi.cast(
12-
'cairo_t **',
13-
id(ctx) + object.__basicsize__)[0],
14-
incref=True)
15-
16-
self.gc.ctx = ctx
21+
self.gc.ctx = backend_cairo._to_context(ctx)
1722

1823

1924
class FigureCanvasGTK3Cairo(backend_gtk3.FigureCanvasGTK3,

tutorials/introductory/usage.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -481,11 +481,8 @@ def my_plotter(ax, data1, data2, param_dict):
481481
# GTK and Cairo
482482
# -------------
483483
#
484-
# Both `GTK2` and `GTK3` have implicit dependencies on PyCairo regardless of the
485-
# specific Matplotlib backend used. Unfortunately the latest release of PyCairo
486-
# for Python3 does not implement the Python wrappers needed for the `GTK3Agg`
487-
# backend. `Cairocffi` can be used as a replacement which implements the correct
488-
# wrapper.
484+
# `GTK3` backends (*both* `GTK3Agg` and `GTK3Cairo`) depend on Cairo
485+
# (pycairo>=1.11.0 or cairocffi).
489486
#
490487
# How do I select PyQt4 or PySide?
491488
# --------------------------------

0 commit comments

Comments
 (0)
0