Skip to content

[ENH]: Add a QtPgfPng backend? #28086

Open

Description

@anntzer

Problem

Per #28084 and a few other older similar issues, some users are confused because they cannot see pgf-generated plots (which can include xelatex/lualatex-specific latex constructs, in particular) interactively, as the interactive guis still use the "standard" latex support.

As it turns out it is relatively easy(?) to implement a minimal "interactive" backend that uses pgf and pdf->png to conversion to interactively display pgf-generated plots. Obviously it has the most terrible performance ever (each draw involves a full tex compilation of the image), but (per the above) it could have some uses...

Proposed solution

Minimum patch implementing the (minimally tested...) backend is below. Test e.g. by setting MPLBACKEND to qtpgfpng and plotting.

diff --git c/lib/matplotlib/backends/backend_qtpgfpng.py i/lib/matplotlib/backends/backend_qtpgfpng.py
new file mode 100644
index 0000000000..f44097dc0b
--- /dev/null
+++ i/lib/matplotlib/backends/backend_qtpgfpng.py
@@ -0,0 +1,27 @@
+from tempfile import TemporaryDirectory
+
+import numpy as np
+import PIL.Image
+
+from .backend_pgf import FigureCanvasPgf
+from .backend_qt import FigureCanvasQT
+from .qt_compat import QtGui
+
+
+class FigureCanvasQTPgfPng(FigureCanvasPgf, FigureCanvasQT):
+    def paintEvent(self, event):
+        with TemporaryDirectory() as tmpdir:
+            self.print_png(f"{tmpdir}/image.png")
+            img = np.asarray(PIL.Image.open(f"{tmpdir}/image.png"))
+        qimage = QtGui.QImage(
+            img, img.shape[1], img.shape[0],
+            QtGui.QImage.Format.Format_RGBA8888)
+        qimage.setDevicePixelRatio(self.device_pixel_ratio)
+        painter = QtGui.QPainter(self)
+        painter.eraseRect(event.rect())
+        painter.drawImage(0, 0, qimage)
+        self._draw_rect_callback(painter)
+        painter.end()
+
+
+FigureCanvas = FigureCanvasQTPgfPng
diff --git c/lib/matplotlib/backends/meson.build i/lib/matplotlib/backends/meson.build
index 1e3e47c0a9..967cab902b 100644
--- c/lib/matplotlib/backends/meson.build
+++ i/lib/matplotlib/backends/meson.build
@@ -19,6 +19,7 @@ python_sources = [
   'backend_qt.py',
   'backend_qtagg.py',
   'backend_qtcairo.py',
+  'backend_qtpgfpng.py',
   'backend_qt5.py',
   'backend_qt5agg.py',
   'backend_qt5cairo.py',
diff --git c/lib/matplotlib/backends/registry.py i/lib/matplotlib/backends/registry.py
index 484d6ed5f2..ac18cc28c9 100644
--- c/lib/matplotlib/backends/registry.py
+++ i/lib/matplotlib/backends/registry.py
@@ -32,7 +32,7 @@ class BackendRegistry:
         "GTK3Agg", "GTK3Cairo", "GTK4Agg", "GTK4Cairo",
         "MacOSX",
         "nbAgg",
-        "QtAgg", "QtCairo", "Qt5Agg", "Qt5Cairo",
+        "QtAgg", "QtCairo", "QtPgfPng", "Qt5Agg", "Qt5Cairo",
         "TkAgg", "TkCairo",
         "WebAgg",
         "WX", "WXAgg", "WXCairo",

(#27913 (comment) is also relevant)

Activity

  1. added this to the v3.10.0 milestone on Apr 16, 2024
  2. tacaswell commented on Apr 16, 2024

    @tacaswell
    Member

    Seems reasonable. It looks like a majority of the work left writing a lot of docs?

  3. anntzer commented on Apr 16, 2024

    @anntzer
    ContributorAuthor

    Yes (including explaining in what context that would be useful). Perhaps also set whatever attributes are needed to mark this as not supporting blitting. Also decide whether we also want the same for the other GUI toolkits (it's just busy work I suspect...).

  4. jklymak commented on Apr 16, 2024

    @jklymak
    Member

    I'm not following why this is a desirable feature?

  5. tacaswell commented on Apr 16, 2024

    @tacaswell
    Member

    Interactive figures are great for exploration or fine tuning (a semi-common workflow for me is to work in an IPython shell using the explicit API to poke at a live figure and then doing %history and copy-pasting-editing that to save). Making this "just work", even with a super slow render, for people who want to output to pgf is small win (now I guess you could do fig.savefig(...) and hope your pdf viewer out-refreshes).

  6. jklymak commented on Apr 16, 2024

    @jklymak
    Member

    Fair, I just think the point of PGF is to write the plot in the PGF language for including in a (**)TeX document, so creating a very slow viewer for the compiled result seems out of scope. I appreciate that the code cost is low, but my concern is that it raises expectations and obscures the point of the PGF backend.

  7. tacaswell commented on Apr 16, 2024

    @tacaswell
    Member

    This only uses public API, maybe the right path is to put this in a new very thin repo and see if it gets any usage?

  8. jklymak commented on Apr 16, 2024

    @jklymak
    Member

    Sounds possible, or even as an example.

    BTW I'm not strongly opposed at all, just making sure we aren't adding a feature that we will later regret.

  9. anntzer commented on Apr 16, 2024

    @anntzer
    ContributorAuthor

    I don't really mind either way; the main question is how to best help users confused by what parts support xelatex syntax and what parts don't (#5234, #28084).

  10. ArchangeGabriel commented on Sep 15, 2024

    @ArchangeGabriel
    Contributor

    Yes please, ever since #5234 indeed I have to workaround the fact interactive display is using latex and not the pgf engine (used to be xelatex at that time, but I’ve long switched to lualatex). So I would very much welcome such a backend. :)

  11. modified the milestones: v3.10.0, v3.11.0 on Oct 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions