You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The _Backend class added in #8773 would be useful for external backends such as ipympl, and is already used by mplcairo. But it is currently marked as a private.
The reason it's already used by mplcairo is because I essentially designed and implemented _Backend for that purpose :-)
I actually think making _Backend public is not best (because @_Backend.export is pretty weird); I have a better solution in mind (starting from something along the lines of #18854, please review :-)). I'll try to post a longer writeup later.
Edit: slightly more elaborated version:
The problem that the _Backend helper is trying to solve is that there is an inheritance-like relationship between backends: if backends were actually classes with FigureCanvas and FigureManager attributes, then backend_qt5agg and backend_qt5cairo could both inherit from backend_qt5 while only overriding FigureCanvas, but keeping the same FigureManager. Previously, this relationship was not really exploited, leading to a lot of duplicated implementations of e.g. new_figure_manager, new_figure_manager_given_canvas, and so on, across backends. I didn't want to further repeat them in mplcairo, so in #8773, I made that inheritance relationship explicit in the (private) _Backend class, while keeping the old API by basically exporting the contents of that class to the module level (via _Backend.export).
I think the better API would be to explicitly acknowledge the inheritance-like relationship in an actual hierarchy of classes. There's two possibilities here:
Make _Backend public (e.g. as BackendBase), and state that a matplotlib backend is either a module that has a "Backend" global which subclasses BackendBase (in which case we look up new_figure_canvas, etc. as attributes of Backend), or (for backcompat) a module with new_figure_canvas, etc. functions. This avoids the need for the slightly weird _Backend.export.
Move that inheritance hierarchy to the FigureCanvas inheritance hierarchy (basically starting with something like Standardize creation of FigureManager from a given FigureCanvas class. #18854), so that backend-generic code (including pyplot) handles everything through the FigureCanvas subclass provided by the backend module. For example, pyplot would create new managers using FigureCanvas.new_manager(), etc. (as usual, keeping the old approach supported for backcompat).
@ianhi Actually, I just realized that there's (I think, probably... but see PS below) a much simpler solution (that should get documented) available for you (because you don't "inherit" from another _Backend). Taking matplotlib/ipympl#305 as a starting point, you can just get rid of _Backend_ipympl, moving FigureCanvas, FigureManager, new_figure_manager_given_figure(), and show() to be toplevel definitions, and that should be all that's needed. (Then your module will not define its own new_figure_manager and draw_if_interactive, which could be considered an API break if you consider that that's public API, but at least Matplotlib will be fine with it because it internally generates a shim to replace it, see
.) In fact, you could perhaps even consider making the additional (transparency handling) code in new_figure_manager_given_figure() to either Canvas.__init__ or FigureManager.__init__ (whichever makes more sense), and then you could then get rid of the definition of new_figure_manager_given_figure as well, again relying on the Matplotlib-generated shim.
(PS: I remembered this point while working on a toy backend; I tried to check whether this works specifically for ipympl but once again I couldn't make Matplotlib work in Jupyter notebooks and I have limited patience in fiddling with that :-))
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!
Activity
anntzer commentedon Mar 1, 2021
The reason it's already used by mplcairo is because I essentially designed and implemented _Backend for that purpose :-)
I actually think making _Backend public is not best (because
@_Backend.exportis pretty weird); I have a better solution in mind (starting from something along the lines of #18854, please review :-)). I'll try to post a longer writeup later.Edit: slightly more elaborated version:
The problem that the _Backend helper is trying to solve is that there is an inheritance-like relationship between backends: if backends were actually classes with FigureCanvas and FigureManager attributes, then backend_qt5agg and backend_qt5cairo could both inherit from backend_qt5 while only overriding FigureCanvas, but keeping the same FigureManager. Previously, this relationship was not really exploited, leading to a lot of duplicated implementations of e.g. new_figure_manager, new_figure_manager_given_canvas, and so on, across backends. I didn't want to further repeat them in mplcairo, so in #8773, I made that inheritance relationship explicit in the (private) _Backend class, while keeping the old API by basically exporting the contents of that class to the module level (via _Backend.export).
I think the better API would be to explicitly acknowledge the inheritance-like relationship in an actual hierarchy of classes. There's two possibilities here:
Make _Backend public (e.g. as BackendBase), and state that a matplotlib backend is either a module that has a "Backend" global which subclasses BackendBase (in which case we look up new_figure_canvas, etc. as attributes of Backend), or (for backcompat) a module with new_figure_canvas, etc. functions. This avoids the need for the slightly weird _Backend.export.
Move that inheritance hierarchy to the FigureCanvas inheritance hierarchy (basically starting with something like Standardize creation of FigureManager from a given FigureCanvas class. #18854), so that backend-generic code (including pyplot) handles everything through the FigureCanvas subclass provided by the backend module. For example, pyplot would create new managers using FigureCanvas.new_manager(), etc. (as usual, keeping the old approach supported for backcompat).
anntzer commentedon Aug 18, 2021
@ianhi Actually, I just realized that there's (I think, probably... but see PS below) a much simpler solution (that should get documented) available for you (because you don't "inherit" from another _Backend). Taking matplotlib/ipympl#305 as a starting point, you can just get rid of
_Backend_ipympl, moving FigureCanvas, FigureManager, new_figure_manager_given_figure(), and show() to be toplevel definitions, and that should be all that's needed. (Then your module will not define its own new_figure_manager and draw_if_interactive, which could be considered an API break if you consider that that's public API, but at least Matplotlib will be fine with it because it internally generates a shim to replace it, seematplotlib/lib/matplotlib/pyplot.py
Lines 245 to 253 in 0a4a10c
Canvas.__init__orFigureManager.__init__(whichever makes more sense), and then you could then get rid of the definition of new_figure_manager_given_figure as well, again relying on the Matplotlib-generated shim.(PS: I remembered this point while working on a toy backend; I tried to check whether this works specifically for ipympl but once again I couldn't make Matplotlib work in Jupyter notebooks and I have limited patience in fiddling with that :-))
github-actions commentedon Nov 22, 2023
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!
anntzer commentedon Nov 22, 2023
Superseded by #22925, I would say.