From 984fba18bcce543f3dd65c5fe5cadfc40e80e690 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Tue, 9 Jan 2018 17:31:47 -0800 Subject: [PATCH 1/4] qt{4,5}cairo backend: the minimal version. --- doc/api/backend_qt4cairo_api.rst | 8 ++ doc/api/backend_qt5cairo_api.rst | 8 ++ doc/api/index_backend_api.rst | 2 + doc/users/next_whats_new/more-cairo.rst | 5 + lib/matplotlib/backends/backend_agg.py | 3 + lib/matplotlib/backends/backend_qt4cairo.py | 6 + lib/matplotlib/backends/backend_qt5.py | 94 ++++++++++++- lib/matplotlib/backends/backend_qt5agg.py | 129 ++---------------- lib/matplotlib/backends/backend_qt5cairo.py | 38 ++++++ lib/matplotlib/rcsetup.py | 14 +- .../tests/test_backends_interactive.py | 1 + 11 files changed, 181 insertions(+), 127 deletions(-) create mode 100644 doc/api/backend_qt4cairo_api.rst create mode 100644 doc/api/backend_qt5cairo_api.rst create mode 100644 doc/users/next_whats_new/more-cairo.rst create mode 100644 lib/matplotlib/backends/backend_qt4cairo.py create mode 100644 lib/matplotlib/backends/backend_qt5cairo.py diff --git a/doc/api/backend_qt4cairo_api.rst b/doc/api/backend_qt4cairo_api.rst new file mode 100644 index 000000000000..590465d7fbc0 --- /dev/null +++ b/doc/api/backend_qt4cairo_api.rst @@ -0,0 +1,8 @@ + +:mod:`matplotlib.backends.backend_qt4cairo` +=========================================== + +.. automodule:: matplotlib.backends.backend_qt4cairo + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_qt5cairo_api.rst b/doc/api/backend_qt5cairo_api.rst new file mode 100644 index 000000000000..73df7ac128a1 --- /dev/null +++ b/doc/api/backend_qt5cairo_api.rst @@ -0,0 +1,8 @@ + +:mod:`matplotlib.backends.backend_qt5cairo` +=========================================== + +.. automodule:: matplotlib.backends.backend_qt5cairo + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/index_backend_api.rst b/doc/api/index_backend_api.rst index ce03c707e902..813c3770214e 100644 --- a/doc/api/index_backend_api.rst +++ b/doc/api/index_backend_api.rst @@ -19,7 +19,9 @@ backends backend_pgf_api.rst backend_ps_api.rst backend_qt4agg_api.rst + backend_qt4cairo_api.rst backend_qt5agg_api.rst + backend_qt5cairo_api.rst backend_svg_api.rst backend_tkagg_api.rst backend_webagg_api.rst diff --git a/doc/users/next_whats_new/more-cairo.rst b/doc/users/next_whats_new/more-cairo.rst new file mode 100644 index 000000000000..8f6f62f630a3 --- /dev/null +++ b/doc/users/next_whats_new/more-cairo.rst @@ -0,0 +1,5 @@ +Cairo rendering for Qt canvases +------------------------------- + +The new ``Qt4Cairo`` and ``Qt5Cairo`` backends allow Qt canvases to use Cairo +rendering instead of Agg. diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index 13a77762f982..a43efda774b9 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -429,6 +429,9 @@ def draw(self): # if toolbar: # toolbar.set_cursor(cursors.WAIT) self.figure.draw(self.renderer) + # A GUI class may be need to update a window using this draw, so + # don't forget to call the superclass. + super(FigureCanvasAgg, self).draw() finally: # if toolbar: # toolbar.set_cursor(toolbar._lastCursor) diff --git a/lib/matplotlib/backends/backend_qt4cairo.py b/lib/matplotlib/backends/backend_qt4cairo.py new file mode 100644 index 000000000000..f94851da382d --- /dev/null +++ b/lib/matplotlib/backends/backend_qt4cairo.py @@ -0,0 +1,6 @@ +from .backend_qt5cairo import _BackendQT5Cairo + + +@_BackendQT5Cairo.export +class _BackendQT4Cairo(_BackendQT5Cairo): + pass diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 6b5e8bbfb54f..4d0bd2438e1b 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -8,6 +8,7 @@ import signal import sys from six import unichr +import traceback import matplotlib @@ -226,19 +227,16 @@ class FigureCanvasQT(QtWidgets.QWidget, FigureCanvasBase): # QtCore.Qt.XButton2: None, } - def _update_figure_dpi(self): - dpi = self._dpi_ratio * self.figure._original_dpi - self.figure._set_dpi(dpi, forward=False) - @_allow_super_init def __init__(self, figure): _create_qApp() super(FigureCanvasQT, self).__init__(figure=figure) - figure._original_dpi = figure.dpi self.figure = figure + # We don't want to scale up the figure DPI more than once. + # Note, we don't handle a signal for changing DPI yet. + figure._original_dpi = figure.dpi self._update_figure_dpi() - self.resize(*self.get_width_height()) # In cases with mixed resolution displays, we need to be careful if the # dpi_ratio changes - in this case we need to resize the canvas # accordingly. We could watch for screenChanged events from Qt, but @@ -248,13 +246,23 @@ def __init__(self, figure): # needed. self._dpi_ratio_prev = None + self._draw_pending = False + self._is_drawing = False + self._draw_rect_callback = lambda painter: None + + self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent) self.setMouseTracking(True) + self.resize(*self.get_width_height()) # Key auto-repeat enabled by default self._keyautorepeat = True palette = QtGui.QPalette(QtCore.Qt.white) self.setPalette(palette) + def _update_figure_dpi(self): + dpi = self._dpi_ratio * self.figure._original_dpi + self.figure._set_dpi(dpi, forward=False) + @property def _dpi_ratio(self): # Not available on Qt4 or some older Qt5. @@ -263,6 +271,26 @@ def _dpi_ratio(self): except AttributeError: return 1 + def _update_dpi(self): + # As described in __init__ above, we need to be careful in cases with + # mixed resolution displays if dpi_ratio is changing between painting + # events. + # Return whether we triggered a resizeEvent (and thus a paintEvent) + # from within this function. + if self._dpi_ratio != self._dpi_ratio_prev: + # We need to update the figure DPI. + self._update_figure_dpi() + self._dpi_ratio_prev = self._dpi_ratio + # The easiest way to resize the canvas is to emit a resizeEvent + # since we implement all the logic for resizing the canvas for + # that event. + event = QtGui.QResizeEvent(self.size(), self.size()) + self.resizeEvent(event) + # resizeEvent triggers a paintEvent itself, so we exit this one + # (after making sure that the event is immediately handled). + return True + return False + def get_width_height(self): w, h = FigureCanvasBase.get_width_height(self) return int(w / self._dpi_ratio), int(h / self._dpi_ratio) @@ -453,6 +481,60 @@ def stop_event_loop(self, event=None): if hasattr(self, "_event_loop"): self._event_loop.quit() + def draw(self): + """Render the figure, and queue a request for a Qt draw. + """ + # The renderer draw is done here; delaying causes problems with code + # that uses the result of the draw() to update plot elements. + if self._is_drawing: + return + self._is_drawing = True + try: + super(FigureCanvasQT, self).draw() + finally: + self._is_drawing = False + self.update() + + def draw_idle(self): + """Queue redraw of the Agg buffer and request Qt paintEvent. + """ + # The Agg draw needs to be handled by the same thread matplotlib + # modifies the scene graph from. Post Agg draw request to the + # current event loop in order to ensure thread affinity and to + # accumulate multiple draw requests from event handling. + # TODO: queued signal connection might be safer than singleShot + if not (self._draw_pending or self._is_drawing): + self._draw_pending = True + QtCore.QTimer.singleShot(0, self._draw_idle) + + def _draw_idle(self): + if self.height() < 0 or self.width() < 0: + self._draw_pending = False + if not self._draw_pending: + return + try: + self.draw() + except Exception: + # Uncaught exceptions are fatal for PyQt5, so catch them instead. + traceback.print_exc() + finally: + self._draw_pending = False + + def drawRectangle(self, rect): + # Draw the zoom rectangle to the QPainter. _draw_rect_callback needs + # to be called at the end of paintEvent. + if rect is not None: + def _draw_rect_callback(painter): + pen = QtGui.QPen(QtCore.Qt.black, 1 / self._dpi_ratio, + QtCore.Qt.DotLine) + painter.setPen(pen) + painter.drawRect(*(pt / self._dpi_ratio for pt in rect)) + else: + def _draw_rect_callback(painter): + return + self._draw_rect_callback = _draw_rect_callback + self.update() + class MainWindow(QtWidgets.QMainWindow): closing = QtCore.Signal() diff --git a/lib/matplotlib/backends/backend_qt5agg.py b/lib/matplotlib/backends/backend_qt5agg.py index 777167132ad6..f0268299bad4 100644 --- a/lib/matplotlib/backends/backend_qt5agg.py +++ b/lib/matplotlib/backends/backend_qt5agg.py @@ -7,7 +7,6 @@ import six import ctypes -import traceback from matplotlib import cbook from matplotlib.transforms import Bbox @@ -19,32 +18,11 @@ from .qt_compat import QT_API -class FigureCanvasQTAggBase(FigureCanvasAgg): - """ - The canvas the figure renders into. Calls the draw and print fig - methods, creates the renderers, etc... - - Attributes - ---------- - figure : `matplotlib.figure.Figure` - A high-level Figure instance - - """ +class FigureCanvasQTAgg(FigureCanvasAgg, FigureCanvasQT): def __init__(self, figure): - super(FigureCanvasQTAggBase, self).__init__(figure=figure) - self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent) - self._agg_draw_pending = False - self._agg_is_drawing = False + super(FigureCanvasQTAgg, self).__init__(figure=figure) self._bbox_queue = [] - self._drawRect = None - - def drawRectangle(self, rect): - if rect is not None: - self._drawRect = [pt / self._dpi_ratio for pt in rect] - else: - self._drawRect = None - self.update() @property @cbook.deprecated("2.1") @@ -57,27 +35,10 @@ def paintEvent(self, e): In Qt, all drawing should be done inside of here when a widget is shown onscreen. """ - # if there is a pending draw, run it now as we need the updated render - # to paint the widget - if self._agg_draw_pending: - self.__draw_idle_agg() - # As described in __init__ above, we need to be careful in cases with - # mixed resolution displays if dpi_ratio is changing between painting - # events. - if self._dpi_ratio != self._dpi_ratio_prev: - # We need to update the figure DPI - self._update_figure_dpi() - self._dpi_ratio_prev = self._dpi_ratio - # The easiest way to resize the canvas is to emit a resizeEvent - # since we implement all the logic for resizing the canvas for - # that event. - event = QtGui.QResizeEvent(self.size(), self.size()) - # We use self.resizeEvent here instead of QApplication.postEvent - # since the latter doesn't guarantee that the event will be emitted - # straight away, and this causes visual delays in the changes. - self.resizeEvent(event) - # resizeEvent triggers a paintEvent itself, so we exit this one. + if self._update_dpi(): + # The dpi update triggered its own paintEvent. return + self._draw_idle() # Only does something if a draw is pending. # if the canvas does not have a renderer, then give up and wait for # FigureCanvasAgg.draw(self) to be called @@ -100,72 +61,20 @@ def paintEvent(self, e): reg = self.copy_from_bbox(bbox) buf = reg.to_string_argb() qimage = QtGui.QImage(buf, w, h, QtGui.QImage.Format_ARGB32) + # Adjust the buf reference count to work around a memory leak bug + # in QImage under PySide on Python 3. + if QT_API == 'PySide' and six.PY3: + ctypes.c_long.from_address(id(buf)).value = 1 if hasattr(qimage, 'setDevicePixelRatio'): # Not available on Qt4 or some older Qt5. qimage.setDevicePixelRatio(self._dpi_ratio) origin = QtCore.QPoint(l, self.renderer.height - t) painter.drawImage(origin / self._dpi_ratio, qimage) - # Adjust the buf reference count to work around a memory - # leak bug in QImage under PySide on Python 3. - if QT_API == 'PySide' and six.PY3: - ctypes.c_long.from_address(id(buf)).value = 1 - # draw the zoom rectangle to the QPainter - if self._drawRect is not None: - pen = QtGui.QPen(QtCore.Qt.black, 1 / self._dpi_ratio, - QtCore.Qt.DotLine) - painter.setPen(pen) - x, y, w, h = self._drawRect - painter.drawRect(x, y, w, h) + self._draw_rect_callback(painter) painter.end() - def draw(self): - """Draw the figure with Agg, and queue a request for a Qt draw. - """ - # The Agg draw is done here; delaying causes problems with code that - # uses the result of the draw() to update plot elements. - if self._agg_is_drawing: - return - - self._agg_is_drawing = True - try: - super(FigureCanvasQTAggBase, self).draw() - finally: - self._agg_is_drawing = False - self.update() - - def draw_idle(self): - """Queue redraw of the Agg buffer and request Qt paintEvent. - """ - # The Agg draw needs to be handled by the same thread matplotlib - # modifies the scene graph from. Post Agg draw request to the - # current event loop in order to ensure thread affinity and to - # accumulate multiple draw requests from event handling. - # TODO: queued signal connection might be safer than singleShot - if not (self._agg_draw_pending or self._agg_is_drawing): - self._agg_draw_pending = True - QtCore.QTimer.singleShot(0, self.__draw_idle_agg) - - def __draw_idle_agg(self, *args): - # if nothing to do, bail - if not self._agg_draw_pending: - return - # we have now tried this function at least once, do not run - # again until re-armed. Doing this here rather than after - # protects against recursive calls triggered through self.draw - # The recursive call is via `repaintEvent` - self._agg_draw_pending = False - # if negative size, bail - if self.height() < 0 or self.width() < 0: - return - try: - # actually do the drawing - self.draw() - except Exception: - # Uncaught exceptions are fatal for PyQt5, so catch them instead. - traceback.print_exc() - def blit(self, bbox=None): """Blit the region in bbox. """ @@ -182,23 +91,13 @@ def blit(self, bbox=None): self.repaint(l, self.renderer.height / self._dpi_ratio - t, w, h) def print_figure(self, *args, **kwargs): - super(FigureCanvasQTAggBase, self).print_figure(*args, **kwargs) + super(FigureCanvasQTAgg, self).print_figure(*args, **kwargs) self.draw() -class FigureCanvasQTAgg(FigureCanvasQTAggBase, FigureCanvasQT): - """ - The canvas the figure renders into. Calls the draw and print fig - methods, creates the renderers, etc. - - Modified to import from Qt5 backend for new-style mouse events. - - Attributes - ---------- - figure : `matplotlib.figure.Figure` - A high-level Figure instance - - """ +@cbook.deprecated("2.2") +class FigureCanvasQTAggBase(FigureCanvasQTAgg): + pass @_BackendQT5.export diff --git a/lib/matplotlib/backends/backend_qt5cairo.py b/lib/matplotlib/backends/backend_qt5cairo.py new file mode 100644 index 000000000000..6778716f5d9e --- /dev/null +++ b/lib/matplotlib/backends/backend_qt5cairo.py @@ -0,0 +1,38 @@ +from .backend_cairo import cairo, FigureCanvasCairo, RendererCairo +from .backend_qt5 import QtCore, QtGui, _BackendQT5, FigureCanvasQT +from .qt_compat import QT_API + + +class FigureCanvasQTCairo(FigureCanvasQT, FigureCanvasCairo): + def __init__(self, figure): + super(FigureCanvasQTCairo, self).__init__(figure=figure) + self._renderer = RendererCairo(self.figure.dpi) + + def paintEvent(self, event): + self._update_dpi() + dpi_ratio = self._dpi_ratio + width = dpi_ratio * self.width() + height = dpi_ratio * self.height() + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) + self._renderer.set_ctx_from_surface(surface) + self._renderer.set_width_height(width, height) + self.figure.draw(self._renderer) + buf = surface.get_data() + qimage = QtGui.QImage(buf, width, height, + QtGui.QImage.Format_ARGB32_Premultiplied) + # Adjust the buf reference count to work around a memory leak bug in + # QImage under PySide on Python 3. + if QT_API == 'PySide' and six.PY3: + ctypes.c_long.from_address(id(buf)).value = 1 + if hasattr(qimage, 'setDevicePixelRatio'): + # Not available on Qt4 or some older Qt5. + qimage.setDevicePixelRatio(dpi_ratio) + painter = QtGui.QPainter(self) + painter.drawImage(0, 0, qimage) + self._draw_rect_callback(painter) + painter.end() + + +@_BackendQT5.export +class _BackendQT5Cairo(_BackendQT5): + FigureCanvas = FigureCanvasQTCairo diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index 7b8baf8aae3a..1a01f0cade9c 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -29,20 +29,22 @@ from matplotlib.fontconfig_pattern import parse_fontconfig_pattern from matplotlib.colors import is_color_like - # Don't let the original cycler collide with our validating cycler from cycler import Cycler, cycler as ccycler -# interactive_bk = ['gtk', 'gtkagg', 'gtkcairo', 'qt4agg', -# 'tkagg', 'wx', 'wxagg', 'webagg'] + # The capitalized forms are needed for ipython at present; this may # change for later versions. - interactive_bk = ['GTK', 'GTKAgg', 'GTKCairo', 'MacOSX', 'Qt4Agg', 'Qt5Agg', 'TkAgg', 'WX', 'WXAgg', 'GTK3Cairo', 'GTK3Agg', 'WebAgg', 'nbAgg'] - - +interactive_bk = ['GTK', 'GTKAgg', 'GTKCairo', 'GTK3Agg', 'GTK3Cairo', + 'MacOSX', + 'nbAgg', + 'Qt4Agg', 'Qt4Cairo', 'Qt5Agg', 'Qt5Cairo', + 'TkAgg', + 'WebAgg', + 'WX', 'WXAgg'] non_interactive_bk = ['agg', 'cairo', 'gdk', 'pdf', 'pgf', 'ps', 'svg', 'template'] all_backends = interactive_bk + non_interactive_bk diff --git a/lib/matplotlib/tests/test_backends_interactive.py b/lib/matplotlib/tests/test_backends_interactive.py index 07d5759bbe0c..ca174878ca13 100644 --- a/lib/matplotlib/tests/test_backends_interactive.py +++ b/lib/matplotlib/tests/test_backends_interactive.py @@ -21,6 +21,7 @@ def _get_testable_interactive_backends(): for deps, backend in [(["cairocffi", "pgi"], "gtk3agg"), (["cairocffi", "pgi"], "gtk3cairo"), (["PyQt5"], "qt5agg"), + (["cairocffi", "PyQt5"], "qt5cairo"), (["tkinter"], "tkagg"), (["wx"], "wxagg")]: reason = None From 64852f37e9682833a68344e6631fef4165a22143 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 4 Feb 2018 16:22:43 -0500 Subject: [PATCH 2/4] DOC: include new API changes documents in api_changes.rst --- doc/api/api_changes.rst | 10 ++++++++++ .../01-11-2017-DS.rst | 0 .../171225-AL-tickbools.rst | 0 .../2017-09-22-AL-contour.rst | 0 .../2017-09-22-AL-removal-of-deprecated-features.rst | 0 .../2017-11-07-JMK.rst | 0 .../2017-11-19_svg_size.rst | 0 .../2017-11-23-AL.rst | 0 .../2017-11-24-AL.rst | 0 .../2017-11-31-AL.rst | 0 .../2017-12-01-AL.rst | 0 .../2017-12-02-AL.rst | 0 .../2017-12-06-imports-AL.rst | 0 .../2017-12-10-TH.rst | 0 .../2017-12-14-JMK.rst | 0 .../2017-12-15-AL.rst | 0 .../2017-12-17-AL.rst | 1 + .../2017-12-26-AL.rst | 0 .../2018-01-29-AL.rst | 0 doc/api/{api_changes => next_api_changes}/README.rst | 4 ++++ .../removed-attributes.rst | 0 21 files changed, 15 insertions(+) rename doc/api/{api_changes => next_api_changes}/01-11-2017-DS.rst (100%) rename doc/api/{api_changes => next_api_changes}/171225-AL-tickbools.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-09-22-AL-contour.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-09-22-AL-removal-of-deprecated-features.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-11-07-JMK.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-11-19_svg_size.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-11-23-AL.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-11-24-AL.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-11-31-AL.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-12-01-AL.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-12-02-AL.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-12-06-imports-AL.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-12-10-TH.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-12-14-JMK.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-12-15-AL.rst (100%) rename doc/api/{api_changes => next_api_changes}/2017-12-17-AL.rst (99%) rename doc/api/{api_changes => next_api_changes}/2017-12-26-AL.rst (100%) rename doc/api/{api_changes => next_api_changes}/2018-01-29-AL.rst (100%) rename doc/api/{api_changes => next_api_changes}/README.rst (89%) rename doc/api/{api_changes => next_api_changes}/removed-attributes.rst (100%) diff --git a/doc/api/api_changes.rst b/doc/api/api_changes.rst index 46a65f203e65..ca6b8b5a65e5 100644 --- a/doc/api/api_changes.rst +++ b/doc/api/api_changes.rst @@ -10,6 +10,16 @@ out what caused the breakage and how to fix it by updating your code. For new features that were added to Matplotlib, please see :ref:`whats-new`. +API Changes in 2.2.0 +==================== + +.. toctree:: + :glob: + :maxdepth: 1 + + next_api_changes/* + + API Changes in 2.1.2 ==================== diff --git a/doc/api/api_changes/01-11-2017-DS.rst b/doc/api/next_api_changes/01-11-2017-DS.rst similarity index 100% rename from doc/api/api_changes/01-11-2017-DS.rst rename to doc/api/next_api_changes/01-11-2017-DS.rst diff --git a/doc/api/api_changes/171225-AL-tickbools.rst b/doc/api/next_api_changes/171225-AL-tickbools.rst similarity index 100% rename from doc/api/api_changes/171225-AL-tickbools.rst rename to doc/api/next_api_changes/171225-AL-tickbools.rst diff --git a/doc/api/api_changes/2017-09-22-AL-contour.rst b/doc/api/next_api_changes/2017-09-22-AL-contour.rst similarity index 100% rename from doc/api/api_changes/2017-09-22-AL-contour.rst rename to doc/api/next_api_changes/2017-09-22-AL-contour.rst diff --git a/doc/api/api_changes/2017-09-22-AL-removal-of-deprecated-features.rst b/doc/api/next_api_changes/2017-09-22-AL-removal-of-deprecated-features.rst similarity index 100% rename from doc/api/api_changes/2017-09-22-AL-removal-of-deprecated-features.rst rename to doc/api/next_api_changes/2017-09-22-AL-removal-of-deprecated-features.rst diff --git a/doc/api/api_changes/2017-11-07-JMK.rst b/doc/api/next_api_changes/2017-11-07-JMK.rst similarity index 100% rename from doc/api/api_changes/2017-11-07-JMK.rst rename to doc/api/next_api_changes/2017-11-07-JMK.rst diff --git a/doc/api/api_changes/2017-11-19_svg_size.rst b/doc/api/next_api_changes/2017-11-19_svg_size.rst similarity index 100% rename from doc/api/api_changes/2017-11-19_svg_size.rst rename to doc/api/next_api_changes/2017-11-19_svg_size.rst diff --git a/doc/api/api_changes/2017-11-23-AL.rst b/doc/api/next_api_changes/2017-11-23-AL.rst similarity index 100% rename from doc/api/api_changes/2017-11-23-AL.rst rename to doc/api/next_api_changes/2017-11-23-AL.rst diff --git a/doc/api/api_changes/2017-11-24-AL.rst b/doc/api/next_api_changes/2017-11-24-AL.rst similarity index 100% rename from doc/api/api_changes/2017-11-24-AL.rst rename to doc/api/next_api_changes/2017-11-24-AL.rst diff --git a/doc/api/api_changes/2017-11-31-AL.rst b/doc/api/next_api_changes/2017-11-31-AL.rst similarity index 100% rename from doc/api/api_changes/2017-11-31-AL.rst rename to doc/api/next_api_changes/2017-11-31-AL.rst diff --git a/doc/api/api_changes/2017-12-01-AL.rst b/doc/api/next_api_changes/2017-12-01-AL.rst similarity index 100% rename from doc/api/api_changes/2017-12-01-AL.rst rename to doc/api/next_api_changes/2017-12-01-AL.rst diff --git a/doc/api/api_changes/2017-12-02-AL.rst b/doc/api/next_api_changes/2017-12-02-AL.rst similarity index 100% rename from doc/api/api_changes/2017-12-02-AL.rst rename to doc/api/next_api_changes/2017-12-02-AL.rst diff --git a/doc/api/api_changes/2017-12-06-imports-AL.rst b/doc/api/next_api_changes/2017-12-06-imports-AL.rst similarity index 100% rename from doc/api/api_changes/2017-12-06-imports-AL.rst rename to doc/api/next_api_changes/2017-12-06-imports-AL.rst diff --git a/doc/api/api_changes/2017-12-10-TH.rst b/doc/api/next_api_changes/2017-12-10-TH.rst similarity index 100% rename from doc/api/api_changes/2017-12-10-TH.rst rename to doc/api/next_api_changes/2017-12-10-TH.rst diff --git a/doc/api/api_changes/2017-12-14-JMK.rst b/doc/api/next_api_changes/2017-12-14-JMK.rst similarity index 100% rename from doc/api/api_changes/2017-12-14-JMK.rst rename to doc/api/next_api_changes/2017-12-14-JMK.rst diff --git a/doc/api/api_changes/2017-12-15-AL.rst b/doc/api/next_api_changes/2017-12-15-AL.rst similarity index 100% rename from doc/api/api_changes/2017-12-15-AL.rst rename to doc/api/next_api_changes/2017-12-15-AL.rst diff --git a/doc/api/api_changes/2017-12-17-AL.rst b/doc/api/next_api_changes/2017-12-17-AL.rst similarity index 99% rename from doc/api/api_changes/2017-12-17-AL.rst rename to doc/api/next_api_changes/2017-12-17-AL.rst index 7e8202bc6f1c..02a3003dd535 100644 --- a/doc/api/api_changes/2017-12-17-AL.rst +++ b/doc/api/next_api_changes/2017-12-17-AL.rst @@ -2,6 +2,7 @@ Removal of deprecated rcParams `````````````````````````````` The following deprecated rcParams have been removed: + - ``axes.color_cycle`` (see ``axes.prop_cycle``), - ``legend.isaxes``, - ``svg.embed_char_paths`` (see ``svg.fonttype``), diff --git a/doc/api/api_changes/2017-12-26-AL.rst b/doc/api/next_api_changes/2017-12-26-AL.rst similarity index 100% rename from doc/api/api_changes/2017-12-26-AL.rst rename to doc/api/next_api_changes/2017-12-26-AL.rst diff --git a/doc/api/api_changes/2018-01-29-AL.rst b/doc/api/next_api_changes/2018-01-29-AL.rst similarity index 100% rename from doc/api/api_changes/2018-01-29-AL.rst rename to doc/api/next_api_changes/2018-01-29-AL.rst diff --git a/doc/api/api_changes/README.rst b/doc/api/next_api_changes/README.rst similarity index 89% rename from doc/api/api_changes/README.rst rename to doc/api/next_api_changes/README.rst index f59c3cb6edc4..c2b71d495ca9 100644 --- a/doc/api/api_changes/README.rst +++ b/doc/api/next_api_changes/README.rst @@ -1,3 +1,7 @@ +Adding API change notes +``````````````````````` + + For changes which require an entry in `api_changes.rst` please create a file in this folder with the name :file:`YYYY-MM-DD-[initials].rst` (ex :file:`2014-07-31-TAC.rst`) with contents following the form: :: diff --git a/doc/api/api_changes/removed-attributes.rst b/doc/api/next_api_changes/removed-attributes.rst similarity index 100% rename from doc/api/api_changes/removed-attributes.rst rename to doc/api/next_api_changes/removed-attributes.rst From 1fda4e032e60841511e356af60d91f4b91eb6501 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 4 Feb 2018 16:23:40 -0500 Subject: [PATCH 3/4] DOC: add deprecation notes for Qt class re-arrangement --- doc/api/next_api_changes/2018-02-03-AL.rst | 73 ++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 doc/api/next_api_changes/2018-02-03-AL.rst diff --git a/doc/api/next_api_changes/2018-02-03-AL.rst b/doc/api/next_api_changes/2018-02-03-AL.rst new file mode 100644 index 000000000000..adcb9f3aeb75 --- /dev/null +++ b/doc/api/next_api_changes/2018-02-03-AL.rst @@ -0,0 +1,73 @@ +Changes to Qt backend class MRO +``````````````````````````````` + +To support both Agg and cairo rendering for Qt backends all of the +non-Agg specific code previously in +:class:`.backend_qt5agg.FigureCanvasQTAggBase` has been moved to +:class:`.backend_qt5.FigureCanvasQT` so it can be shared with the cairo +implementation. The :meth:`.FigureCanvasQTAggBase.paintEvent`, +:meth:`.FigureCanvasQTAggBase.blit`, and +:meth:`.FigureCanvasQTAggBase.print_figure` methods have moved to +:meth:`.FigureCanvasQTAgg.paintEvent`, :meth:`.FigureCanvasQTAgg.blit`, and +:meth:`.FigureCanvasQTAgg.print_figure`. The first two methods assume that +the instance is also a :class:`QWidget` so to use +:class:`FigureCanvasQTAggBase` it was required to multiple inherit +from a :class:`QWidget` sub-class. + +Having moved all of it's methods either up or down the class hierarchy +:class:`FigureCanvasQTAggBase` has been deprecated. To do this with +out warning and to preserve as much API as possible, +:class:`.backend_qt5.FigureCanvasQTAggBase` now inherits from +:class:`.backend_qt5.FigureCanvasQTAgg`. + +The MRO for :class:`FigureCanvasQTAgg` and +:class:`FigureCanvasQTAggBase` used to be :: + + + [matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg, + matplotlib.backends.backend_qt5agg.FigureCanvasQTAggBase, + matplotlib.backends.backend_agg.FigureCanvasAgg, + matplotlib.backends.backend_qt5.FigureCanvasQT, + PyQt5.QtWidgets.QWidget, + PyQt5.QtCore.QObject, + sip.wrapper, + PyQt5.QtGui.QPaintDevice, + sip.simplewrapper, + matplotlib.backend_bases.FigureCanvasBase, + object] + +and :: + + + [matplotlib.backends.backend_qt5agg.FigureCanvasQTAggBase, + matplotlib.backends.backend_agg.FigureCanvasAgg, + matplotlib.backend_bases.FigureCanvasBase, + object] + + +respectively. They are now :: + + [matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg, + matplotlib.backends.backend_agg.FigureCanvasAgg, + matplotlib.backends.backend_qt5.FigureCanvasQT, + PyQt5.QtWidgets.QWidget, + PyQt5.QtCore.QObject, + sip.wrapper, + PyQt5.QtGui.QPaintDevice, + sip.simplewrapper, + matplotlib.backend_bases.FigureCanvasBase, + object] + +and :: + + [matplotlib.backends.backend_qt5agg.FigureCanvasQTAggBase, + matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg, + matplotlib.backends.backend_agg.FigureCanvasAgg, + matplotlib.backends.backend_qt5.FigureCanvasQT, + PyQt5.QtWidgets.QWidget, + PyQt5.QtCore.QObject, + sip.wrapper, + PyQt5.QtGui.QPaintDevice, + sip.simplewrapper, + matplotlib.backend_bases.FigureCanvasBase, + object] From afe6c1ab9add48057128e39aee57a7855959ffbe Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 5 Feb 2018 15:11:42 -0500 Subject: [PATCH 4/4] DOC: copy-edit --- doc/api/next_api_changes/2018-02-03-AL.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/next_api_changes/2018-02-03-AL.rst b/doc/api/next_api_changes/2018-02-03-AL.rst index adcb9f3aeb75..d011616d8975 100644 --- a/doc/api/next_api_changes/2018-02-03-AL.rst +++ b/doc/api/next_api_changes/2018-02-03-AL.rst @@ -14,7 +14,7 @@ the instance is also a :class:`QWidget` so to use :class:`FigureCanvasQTAggBase` it was required to multiple inherit from a :class:`QWidget` sub-class. -Having moved all of it's methods either up or down the class hierarchy +Having moved all of its methods either up or down the class hierarchy :class:`FigureCanvasQTAggBase` has been deprecated. To do this with out warning and to preserve as much API as possible, :class:`.backend_qt5.FigureCanvasQTAggBase` now inherits from