Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 310e707

Browse files
committed
optional use of preview.sty in usetex mode
svn path=/trunk/matplotlib/; revision=6734
1 parent 1f054a7 commit 310e707

File tree

8 files changed

+249
-17
lines changed

8 files changed

+249
-17
lines changed

CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
2009-01-05 optional use of preview.sty in usetex mode. - JJL
2+
13
2009-01-02 Allow multipage pdf files. - JKS
24

35
2008-12-31 Improve pdf usetex by adding support for font effects
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
2+
import matplotlib
3+
import matplotlib.pyplot as plt
4+
import matplotlib.axes as maxes
5+
6+
class Axes(maxes.Axes):
7+
"""
8+
A hackish way to simultaneously draw texts w/ usetex=True and
9+
usetex=False in the same figure. It does not work in the ps backend.
10+
"""
11+
def __init__(self, *kl, **kw):
12+
self.usetex = kw.pop("usetex", "False")
13+
self.preview = kw.pop("preview", "False")
14+
15+
maxes.Axes.__init__(self, *kl, **kw)
16+
17+
def draw(self, renderer):
18+
usetex = plt.rcParams["text.usetex"]
19+
preview = plt.rcParams["text.latex.preview"]
20+
plt.rcParams["text.usetex"] = self.usetex
21+
plt.rcParams["text.latex.preview"] = self.preview
22+
23+
maxes.Axes.draw(self, renderer)
24+
25+
plt.rcParams["text.usetex"] = usetex
26+
plt.rcParams["text.latex.preview"] = preview
27+
28+
Subplot = maxes.subplot_class_factory(Axes)
29+
30+
31+
def test_window_extent(ax, usetex, preview):
32+
33+
va = "baseline"
34+
ax.xaxis.set_visible(False)
35+
ax.yaxis.set_visible(False)
36+
37+
38+
#t = ax.text(0., 0., r"mlp", va="baseline", size=150)
39+
text_kw = dict(va=va,
40+
size=50,
41+
bbox=dict(pad=0., ec="k", fc="none"))
42+
43+
44+
test_strings = ["lg", r"$\frac{1}{2}\pi$",
45+
r"$p^{3^A}$", r"$p_{3_2}$"]
46+
47+
ax.axvline(0, color="r")
48+
49+
for i, s in enumerate(test_strings):
50+
51+
ax.axhline(i, color="r")
52+
ax.text(0., 3-i, s, **text_kw)
53+
54+
ax.set_xlim(-0.1,1.1)
55+
ax.set_ylim(-.8,3.9)
56+
57+
58+
ax.set_title("usetex=%s\npreview=%s" % (str(usetex), str(preview)))
59+
60+
61+
62+
F = plt.figure(figsize=(2.*3,6.5))
63+
64+
for i, usetex, preview in [[0, False, False],
65+
[1, True, False],
66+
[2, True, True]]:
67+
ax = Subplot(F, 1, 3, i+1, usetex=usetex, preview=preview)
68+
F.add_subplot(ax)
69+
F.subplots_adjust(top=0.85)
70+
71+
test_window_extent(ax, usetex=usetex, preview=preview)
72+
73+
74+
plt.draw()
75+
plt.show()
76+

lib/matplotlib/backends/backend_agg.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,10 @@ def get_text_width_height_descent(self, s, prop, ismath):
146146
# todo: handle props
147147
size = prop.get_size_in_points()
148148
texmanager = self.get_texmanager()
149-
Z = texmanager.get_grey(s, size, self.dpi)
150-
m,n = Z.shape
151-
# TODO: descent of TeX text (I am imitating backend_ps here -JKS)
152-
return n, m, 0
149+
fontsize = prop.get_size_in_points()
150+
w, h, d = texmanager.get_text_width_height_descent(s, fontsize,
151+
renderer=self)
152+
return w, h, d
153153

154154
if ismath:
155155
ox, oy, width, height, descent, fonts, used_characters = \

lib/matplotlib/backends/backend_pdf.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ def createType1Descriptor(self, t1font, fontfile):
612612
if 0: flags |= 1 << 18 # TODO: force bold
613613

614614
ft2font = FT2Font(fontfile)
615-
615+
616616
descriptor = {
617617
'Type': Name('FontDescriptor'),
618618
'FontName': Name(t1font.prop['FontName']),
@@ -1602,12 +1602,10 @@ def get_text_width_height_descent(self, s, prop, ismath):
16021602
if rcParams['text.usetex']:
16031603
texmanager = self.get_texmanager()
16041604
fontsize = prop.get_size_in_points()
1605-
dvifile = texmanager.make_dvi(s, fontsize)
1606-
dvi = dviread.Dvi(dvifile, 72)
1607-
page = iter(dvi).next()
1608-
dvi.close()
1609-
# A total height (including the descent) needs to be returned.
1610-
return page.width, page.height+page.descent, page.descent
1605+
w, h, d = texmanager.get_text_width_height_descent(s, fontsize,
1606+
renderer=self)
1607+
return w, h, d
1608+
16111609
if ismath:
16121610
w, h, d, glyphs, rects, used_characters = \
16131611
self.mathtext_parser.parse(s, 72, prop)

lib/matplotlib/backends/backend_ps.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -274,12 +274,9 @@ def get_text_width_height_descent(self, s, prop, ismath):
274274
if rcParams['text.usetex']:
275275
texmanager = self.get_texmanager()
276276
fontsize = prop.get_size_in_points()
277-
l,b,r,t = texmanager.get_ps_bbox(s, fontsize)
278-
w = (r-l)
279-
h = (t-b)
280-
# TODO: We need a way to get a good baseline from
281-
# text.usetex
282-
return w, h, 0
277+
w, h, d = texmanager.get_text_width_height_descent(s, fontsize,
278+
renderer=self)
279+
return w, h, d
283280

284281
if ismath:
285282
width, height, descent, pswriter, used_characters = \

lib/matplotlib/mpl-data/matplotlib.conf.template

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ units = False
357357
preamble = []
358358
# a boolean
359359
unicode = False
360+
# a boolean
361+
preview = False
360362

361363
[verbose]
362364
# a file name or 'sys.stdout'

lib/matplotlib/rcsetup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ def __call__(self, s):
386386
'text.usetex' : [False, validate_bool],
387387
'text.latex.unicode' : [False, validate_bool],
388388
'text.latex.preamble' : [[''], validate_stringlist],
389+
'text.latex.preview' : [False, validate_bool],
389390
'text.dvipnghack' : [None, validate_bool_maybe_none],
390391
'text.fontstyle' : ['normal', str],
391392
'text.fontangle' : ['normal', str],

lib/matplotlib/texmanager.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
import matplotlib as mpl
4646
from matplotlib import rcParams
4747
from matplotlib._png import read_png
48+
import matplotlib.dviread as dviread
49+
import re
4850

4951
DEBUG = False
5052

@@ -262,12 +264,83 @@ def make_tex(self, tex, fontsize):
262264

263265
return texfile
264266

267+
268+
_re_vbox = re.compile(r"MatplotlibBox:\(([\d.]+)pt\+([\d.]+)pt\)x([\d.]+)pt")
269+
270+
def make_tex_preview(self, tex, fontsize):
271+
"""
272+
Generate a tex file to render the tex string at a specific
273+
font size. It uses the preview.sty to determin the dimension
274+
(width, height, descent) of the output.
275+
276+
returns the file name
277+
"""
278+
basefile = self.get_basefile(tex, fontsize)
279+
texfile = '%s.tex'%basefile
280+
fh = file(texfile, 'w')
281+
custom_preamble = self.get_custom_preamble()
282+
fontcmd = {'sans-serif' : r'{\sffamily %s}',
283+
'monospace' : r'{\ttfamily %s}'}.get(self.font_family,
284+
r'{\rmfamily %s}')
285+
tex = fontcmd % tex
286+
287+
if rcParams['text.latex.unicode']:
288+
unicode_preamble = """\usepackage{ucs}
289+
\usepackage[utf8x]{inputenc}"""
290+
else:
291+
unicode_preamble = ''
292+
293+
294+
295+
# newbox, setbox, immediate, etc. are used to find the box
296+
# extent of the rendered text.
297+
298+
299+
s = r"""\documentclass{article}
300+
%s
301+
%s
302+
%s
303+
\usepackage[active,showbox,tightpage]{preview}
304+
%%\usepackage[papersize={72in,72in}, body={70in,70in}, margin={1in,1in}]{geometry}
305+
306+
%% we override the default showbox as it is treated as an error and makes
307+
%% the exit status not zero
308+
\def\showbox#1{\immediate\write16{MatplotlibBox:(\the\ht#1+\the\dp#1)x\the\wd#1}}
309+
310+
\begin{document}
311+
\begin{preview}
312+
{\fontsize{%f}{%f}%s}
313+
\end{preview}
314+
\end{document}
315+
""" % (self._font_preamble, unicode_preamble, custom_preamble,
316+
fontsize, fontsize*1.25, tex)
317+
if rcParams['text.latex.unicode']:
318+
fh.write(s.encode('utf8'))
319+
else:
320+
try:
321+
fh.write(s)
322+
except UnicodeEncodeError, err:
323+
mpl.verbose.report("You are using unicode and latex, but have "
324+
"not enabled the matplotlib 'text.latex.unicode' "
325+
"rcParam.", 'helpful')
326+
raise
327+
328+
fh.close()
329+
330+
return texfile
331+
332+
265333
def make_dvi(self, tex, fontsize):
266334
"""
267335
generates a dvi file containing latex's layout of tex string
268336
269337
returns the file name
270338
"""
339+
340+
341+
if rcParams['text.latex.preview']:
342+
return self.make_dvi_preview(tex, fontsize)
343+
271344
basefile = self.get_basefile(tex, fontsize)
272345
dvifile = '%s.dvi'% basefile
273346

@@ -298,6 +371,55 @@ def make_dvi(self, tex, fontsize):
298371

299372
return dvifile
300373

374+
375+
def make_dvi_preview(self, tex, fontsize):
376+
"""
377+
generates a dvi file containing latex's layout of tex
378+
string. It calls make_tex_preview() method and store the size
379+
information (width, height, descent) in a separte file.
380+
381+
returns the file name
382+
"""
383+
basefile = self.get_basefile(tex, fontsize)
384+
dvifile = '%s.dvi'% basefile
385+
baselinefile = '%s.baseline'% basefile
386+
387+
if DEBUG or not os.path.exists(dvifile) or \
388+
not os.path.exists(baselinefile):
389+
texfile = self.make_tex_preview(tex, fontsize)
390+
outfile = basefile+'.output'
391+
command = self._get_shell_cmd('cd "%s"'% self.texcache,
392+
'latex -interaction=nonstopmode %s > "%s"'\
393+
%(os.path.split(texfile)[-1], outfile))
394+
mpl.verbose.report(command, 'debug')
395+
exit_status = os.system(command)
396+
try:
397+
fh = file(outfile)
398+
report = fh.read()
399+
fh.close()
400+
401+
except IOError:
402+
report = 'No latex error report available.'
403+
if exit_status:
404+
raise RuntimeError(('LaTeX was not able to process the following \
405+
string:\n%s\nHere is the full report generated by LaTeX: \n\n'% repr(tex)) + report)
406+
else: mpl.verbose.report(report, 'debug')
407+
408+
# find the box extent information in the latex output
409+
# file and store them in ".baseline" file
410+
m = TexManager._re_vbox.search(report)
411+
open(basefile+'.baseline',"w").write(" ".join(m.groups()))
412+
413+
for fname in glob.glob(basefile+'*'):
414+
if fname.endswith('dvi'): pass
415+
elif fname.endswith('tex'): pass
416+
elif fname.endswith('baseline'): pass
417+
else:
418+
try: os.remove(fname)
419+
except OSError: pass
420+
421+
return dvifile
422+
301423
def make_png(self, tex, fontsize, dpi):
302424
"""
303425
generates a png file containing latex's rendering of tex string
@@ -441,3 +563,37 @@ def get_rgba(self, tex, fontsize=None, dpi=None, rgb=(0,0,0)):
441563
self.rgba_arrayd[key] = Z
442564

443565
return Z
566+
567+
568+
def get_text_width_height_descent(self, tex, fontsize, renderer=None):
569+
"""
570+
return width, heigth and descent of the text.
571+
"""
572+
573+
if renderer:
574+
dpi_fraction = renderer.points_to_pixels(1.)
575+
else:
576+
dpi_fraction = 1.
577+
578+
if rcParams['text.latex.preview']:
579+
# use preview.sty
580+
basefile = self.get_basefile(tex, fontsize)
581+
baselinefile = '%s.baseline'% basefile
582+
583+
584+
if DEBUG or not os.path.exists(baselinefile):
585+
dvifile = self.make_dvi_preview(tex, fontsize)
586+
587+
l = open(baselinefile).read().split()
588+
height, depth, width = [float(l1)*dpi_fraction for l1 in l]
589+
return width, height+depth, depth
590+
591+
else:
592+
# use dviread. It sometimes returns a wrong descent.
593+
dvifile = self.make_dvi(tex, fontsize)
594+
dvi = dviread.Dvi(dvifile, 72*dpi_fraction)
595+
page = iter(dvi).next()
596+
dvi.close()
597+
# A total height (including the descent) needs to be returned.
598+
return page.width, page.height+page.descent, page.descent
599+

0 commit comments

Comments
 (0)