-
-
Save f0k/f8c87ffd82488c2ed303989592bf4ebd to your computer and use it in GitHub Desktop.
Matplotlib PGF backend with support for interpolation='none'
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
Version of the PGF backend that supports interpolation='none' for imshow(). | |
To use it, copy it somewhere it can be found by Python and set the backend | |
to 'module://backend_mypgf'. For example, this can be done by: | |
import matplotlib as mpl | |
mpl.use('module://backend_mypgf') | |
Only requires two functions to be overridden in RendererPgf, but needs to | |
import or override a lot of additional boilerplate. | |
Author: Jan Schlüter | |
""" | |
from __future__ import (absolute_import, division, print_function, | |
unicode_literals) | |
import os | |
import numpy as np | |
import matplotlib as mpl | |
from matplotlib.backends.backend_pgf import (FigureCanvasPgf, | |
FigureManagerPgf, | |
RendererPgf, | |
writeln, | |
draw_if_interactive, | |
get_preamble, | |
get_fontspec, | |
MixedModeRenderer, | |
Figure, | |
_png, | |
) | |
class MyRendererPgf(RendererPgf): | |
def option_scale_image(self): | |
""" | |
pgf backend supports arbitrary scaling of image. | |
""" | |
return True | |
def draw_image(self, gc, x, y, im, dx=None, dy=None, trans=None): | |
# save the images to png files | |
path = os.path.dirname(self.fh.name) | |
fname = os.path.splitext(os.path.basename(self.fh.name))[0] | |
fname_img = "%s-img%d.png" % (fname, self.image_counter) | |
self.image_counter += 1 | |
_png.write_png(np.array(im)[::-1], os.path.join(path, fname_img)) | |
# reference the image in the pgf picture | |
writeln(self.fh, r"\begin{pgfscope}") | |
self._print_pgf_clip(gc) | |
h, w = im.get_size_out() | |
if dy: | |
h = dy | |
if dx: | |
w = dx | |
f = 1. / self.dpi # from display coords to inch | |
if (trans is not None and | |
not isinstance(trans, mpl.transforms.IdentityTransform)): | |
t1, t2, t3, t4, t5, t6 = trans.frozen().to_values() | |
writeln(self.fh, r"\makeatletter\pgfsys@transformcm{%f}{%f}{%f}{%f}{%fin}{%fin}\makeatother" % (t1, t2, t3, t4, t5 * f, t6 * f)) | |
interp = str(trans is None).lower() | |
writeln(self.fh, r"\pgftext[at=\pgfqpoint{%fin}{%fin},left,bottom]{\pgfimage[interpolate=%s,width=%fin,height=%fin]{%s}}" % (x * f, y * f, interp, w * f, h * f, fname_img)) | |
writeln(self.fh, r"\end{pgfscope}") | |
class MyFigureCanvasPgf(FigureCanvasPgf): | |
def _print_pgf_to_fh(self, fh, *args, **kwargs): | |
if kwargs.get("dryrun", False): | |
renderer = MyRendererPgf(self.figure, None, dummy=True) | |
self.figure.draw(renderer) | |
return | |
header_text = """%% Creator: Matplotlib, PGF backend | |
%% | |
%% To include the figure in your LaTeX document, write | |
%% \\input{<filename>.pgf} | |
%% | |
%% Make sure the required packages are loaded in your preamble | |
%% \\usepackage{pgf} | |
%% | |
%% Figures using additional raster images can only be included by \input if | |
%% they are in the same directory as the main LaTeX file. For loading figures | |
%% from other directories you can use the `import` package | |
%% \\usepackage{import} | |
%% and then include the figures with | |
%% \\import{<path to file>}{<filename>.pgf} | |
%% | |
""" | |
# append the preamble used by the backend as a comment for debugging | |
header_info_preamble = ["%% Matplotlib used the following preamble"] | |
for line in get_preamble().splitlines(): | |
header_info_preamble.append("%% " + line) | |
for line in get_fontspec().splitlines(): | |
header_info_preamble.append("%% " + line) | |
header_info_preamble.append("%%") | |
header_info_preamble = "\n".join(header_info_preamble) | |
# get figure size in inch | |
w, h = self.figure.get_figwidth(), self.figure.get_figheight() | |
dpi = self.figure.get_dpi() | |
# create pgfpicture environment and write the pgf code | |
fh.write(header_text) | |
fh.write(header_info_preamble) | |
fh.write("\n") | |
writeln(fh, r"\begingroup") | |
writeln(fh, r"\makeatletter") | |
writeln(fh, r"\begin{pgfpicture}") | |
writeln(fh, r"\pgfpathrectangle{\pgfpointorigin}{\pgfqpoint{%fin}{%fin}}" % (w, h)) | |
writeln(fh, r"\pgfusepath{use as bounding box, clip}") | |
_bbox_inches_restore = kwargs.pop("bbox_inches_restore", None) | |
renderer = MixedModeRenderer(self.figure, w, h, dpi, | |
MyRendererPgf(self.figure, fh), | |
bbox_inches_restore=_bbox_inches_restore) | |
self.figure.draw(renderer) | |
# end the pgfpicture environment | |
writeln(fh, r"\end{pgfpicture}") | |
writeln(fh, r"\makeatother") | |
writeln(fh, r"\endgroup") | |
def get_renderer(self): | |
return MyRendererPgf(self.figure, None, dummy=True) | |
############################################################################### | |
FigureCanvas = MyFigureCanvasPgf | |
FigureManager = FigureManagerPgf | |
def new_figure_manager(num, *args, **kwargs): | |
""" | |
Create a new figure manager instance | |
""" | |
# if a main-level app must be created, this is the usual place to | |
# do it -- see backend_wx, backend_wxagg and backend_tkagg for | |
# examples. Not all GUIs require explicit instantiation of a | |
# main-level app (egg backend_gtk, backend_gtkagg) for pylab | |
FigureClass = kwargs.pop('FigureClass', Figure) | |
thisFig = FigureClass(*args, **kwargs) | |
return new_figure_manager_given_figure(num, thisFig) | |
def new_figure_manager_given_figure(num, figure): | |
""" | |
Create a new figure manager instance for the given figure. | |
""" | |
canvas = MyFigureCanvasPgf(figure) | |
manager = FigureManagerPgf(canvas, num) | |
return manager |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment