2025-06-07 20:06:19 +02:00

63 lines
1.8 KiB
Python

# SPDX-License-Identifier: CC0-1.0
import sys
from subprocess import Popen, PIPE
import warnings
from matplotlib import interactive, is_interactive
from matplotlib._pylab_helpers import Gcf
from matplotlib.backend_bases import (_Backend, FigureManagerBase)
from matplotlib.backends.backend_agg import FigureCanvasAgg
# XXX heuristic for interactive repl
if sys.flags.interactive:
interactive(True)
class FigureManagerSixel(FigureManagerBase):
def show(self):
try:
print()
p = Popen(["convert", 'png:-', 'sixel:-'], stdin=PIPE)
self.canvas.figure.savefig(p.stdin, bbox_inches="tight", format='png')
p.stdin.close()
p.wait()
except FileNotFoundError:
warnings.warn("Unable to convert plot to sixel format: Imagemagick not found.")
class FigureCanvasSixel(FigureCanvasAgg):
manager_class = FigureManagerSixel
@_Backend.export
class _BackendSixelAgg(_Backend):
FigureCanvas = FigureCanvasSixel
FigureManager = FigureManagerSixel
# Noop function instead of None signals that
# this is an "interactive" backend
mainloop = lambda: None
# XXX: `draw_if_interactive` isn't really intended for
# on-shot rendering. We run the risk of being called
# on a figure that isn't completely rendered yet, so
# we skip draw calls for figures that we detect as
# not being fully initialized yet. Our heuristic for
# that is the presence of axes on the figure.
@classmethod
def draw_if_interactive(cls):
manager = Gcf.get_active()
if is_interactive() and manager.canvas.figure.get_axes():
cls.show()
@classmethod
def show(cls, *args, **kwargs):
_Backend.show(*args, **kwargs)
Gcf.destroy_all()